在 WPF 中仅使用 XAML 将元素按其中心(而不是左上角)定位在画布内

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13219321/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 06:04:41  来源:igfitidea点击:

Positioning an element inside the Canvas by its center (instead of the top left corner) using only XAML in WPF

wpfxamlcanvascentering

提问by Ark-kun

The common question about positioning an element inside a Canvasis "How to position the center of element (instead of the top left corner)".

关于在 a 内定位元素的常见问题Canvas是“如何定位元素的中心(而不是左上角)”。

Several solutions are presented, but they all have drawbacks.

提出了几种解决方案,但它们都有缺点。

The easiest solution is to accommodate the element size during while setting the Canvas.Leftand Canvas.Topproperties programmatically. This works, but only once. This solution doesn't support bindings and it will break when the element size is changed. You also cannot set the Canvas.Leftor Canvas.Topusing

最简单的解决方案是在以编程方式设置Canvas.LeftCanvas.Top属性时适应元素大小。这有效,但只有一次。此解决方案不支持绑定,并且会在元素大小更改时中断。您也不能设置Canvas.LeftCanvas.Top使用

Another set of solutions involve translate transformations utilizing either RenderTransformor Margin. These solutions require binding some property to the -0.5 * Widthor -0.5 * Height. Such binding requires creating a custom ValueConverterand is impossible to create using only XAML.

另一组解决方案涉及使用RenderTransform或 的翻译转换Margin。这些解决方案需要将某些属性绑定到-0.5 * Widthor -0.5 * Height。此类绑定需要创建自定义ValueConverter,仅使用 XAML 无法创建。

So, is there a simple way to position an element inside canvas so that its Canvas.Leftand Canvas.Topcorrespond to the element's center and both size and position properties can be bound to some other properties?

那么,是否有一种简单的方法可以在画布内定位元素,使其Canvas.LeftCanvas.Top对应于元素的中心,并且大小和位置属性都可以绑定到其他一些属性?

采纳答案by Ark-kun

XAML and bindings seem very powerful, but sometimes there are simple problems that require very complex solutions. In my bindings library creating such binding would be as easy as writing element.Center = positionor element.TopLeft = position - element.Size / 2, but don't let me get carried away.

XAML 和绑定看起来非常强大,但有时也存在需要非常复杂的解决方案的简单问题。在我的绑定库中,创建这样的绑定就像编写element.Center = positionor一样简单element.TopLeft = position - element.Size / 2,但不要让我得意忘形。

I've found a very simple solution which uses only XAML and supports binding both size and position properties of the element. It seems that when the WPF control with alignment set too Stretchor Centeris placed inside the canvas, the element "gravitates" towards centering as the (Canvas.Left, Canvas.Top)point (the state that we desire), but is stopped by the "angle plate" placed at the same (Canvas.Left, Canvas.Top)point. How do I know about this "gravitation"? It's evident when you ease the block by setting the Marginof the element to a negative value. Setting the negative margin allows the element to move towards its center goal. The element moves until the Marginreaches (-Height / 2, -Width / 2)so that the element becomes perfectly centered at the (Canvas.Left, Canvas.Top)point. Further changes don't cause any movement since the element is already perfectly positioned.

我找到了一个非常简单的解决方案,它只使用 XAML 并支持绑定元素的大小和位置属性。似乎当 WPF 控件也设置了对齐方式StretchCenter放置在画布内时,元素“倾向于”以(Canvas.Left, Canvas.Top)点为中心(我们想要的状态),但被放置在同(Canvas.Left, Canvas.Top)一点的“角板”阻止. 我怎么知道这个“引力”?当您通过将Margin元素的 设置为负值来缓和块时,这很明显。设置负边距允许元素向其中心目标移动。元素移动直到Margin到达,(-Height / 2, -Width / 2)以便元素完美地居中(Canvas.Left, Canvas.Top)观点。进一步的更改不会导致任何移动,因为元素已经完美定位。

Solution: set Margin="-1000000".

解决办法:设置Margin="-1000000"

So in the following code the ellipses are both centered at the (200, 200) point. The first ellipse has Leftand Topproperties corresponding to the ellipse center allowing to easily bind them with some other objects' properties.

所以在下面的代码中,椭圆都以 (200, 200) 点为中心。第一个椭圆具有LeftTop椭圆中心相对应的属性,可以轻松地将它们与其他一些对象的属性绑定。

<Canvas>
    <Ellipse Width="100" Height="100" Canvas.Left="200" Canvas.Top="200" Opacity="0.5" Fill="Red" Margin="-100000" />
    <Ellipse Width="100" Height="100" Canvas.Left="150" Canvas.Top="150" Opacity="0.5" Fill="Blue" />
</Canvas>

The bad thing is this solution only work in WPF. Silverlight and WinRT don't have the described behavior.

不好的是这个解决方案只适用于 WPF。Silverlight 和 WinRT 没有描述的行为。

回答by Clemens

Even simpler, at least for Shapes, would be to use a Path with an appropriate Geometry:

更简单的,至少对于形状来说,是使用具有适当几何形状的路径:

<Canvas>
    <Path Canvas.Left="200" Canvas.Top="200" Fill="Red" Opacity="0.5">
        <Path.Data>
            <EllipseGeometry RadiusX="50" RadiusY="50"/>
        </Path.Data>
    </Path>
</Canvas>

回答by Japa Illo

I solved this by putting the canvas into the bottom-right cell of a 2x2 grid. That makes the 0,0 coordinate the center of the grid, and then you can do all your drawing relative to that.

我通过将画布放入 2x2 网格的右下角单元格解决了这个问题。这使得 0,0 坐标成为网格的中心,然后您可以相对于它进行所有绘图。

回答by sky-dev

This solution worked for me Center text at a given point on a WPF Canvas. He uses a MultiBinding and a custom Converter to adjust the margin on his element. Brilliant!

这个解决方案对我有用 WPF Canvas 上给定点的中心文本。他使用 MultiBinding 和自定义转换器来调整元素的边距。杰出的!