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

蹲街弑〆低调 提交于 2019-11-27 01:54:15

问题


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

  • WPF: Resizing a circle, keeping the center point instead of TopLeft?
  • WPF Center Ellipse at X, Y
  • WPF element positioning on 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.Left and Canvas.Top properties 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.Left or Canvas.Top using

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

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


回答1:


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 = position or element.TopLeft = position - element.Size / 2, but don't let me get carried away.

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 Stretch or Center is 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 Margin of the element to a negative value. Setting the negative margin allows the element to move towards its center goal. The element moves until the Margin reaches (-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.

Solution: set Margin="-1000000".

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

<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.




回答2:


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>



回答3:


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.




回答4:


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!



来源:https://stackoverflow.com/questions/13219321/positioning-an-element-inside-the-canvas-by-its-center-instead-of-the-top-left

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!