WPF:如何在Canvas中的中心制作(0,0)

dec*_*jau 15 wpf canvas coordinate-systems

WPF Canvas的坐标系从控件左上角的(0,0)开始.

例如,设置以下内容将使我的控件显示在左上角:

<Control Canvas.Left="0" Canvas.Top="0">
Run Code Online (Sandbox Code Playgroud)

如何将其更改为标准笛卡尔坐标

基本上:

  • (0,0)在中心
  • 翻转Y.

我注意到这篇文章很相似,但它没有谈到翻译坐标系.我尝试添加TranslateTransform,但我无法使其工作.

Ray*_*rns 27

无需创建自定义面板.画布会做得很好.只需将其包装在另一个控件(如边框)​​中,居中,将其设置为零,然后使用RenderTransform将其翻转:

<Border>
  <Canvas HorizontalAlignment="Center" VerticalAlignment="Center"
          Width="0" Height="0"
          RenderTransform="1 0 0 -1 0 0">
    ...
  </Canvas>
</Border>
Run Code Online (Sandbox Code Playgroud)

您可以执行此操作,画布中的所有内容仍将显示,除了(0,0)将位于包含控件的中心(在本例中为边框的中心),+ Y将向上而不是向下.

同样,不需要为此创建自定义面板.


dec*_*jau 7

这很容易做到.我使用.NET Reflector查看了原始的Canvas代码,并注意到实现非常简单.唯一需要的是覆盖该功能ArrangeOverride(...)

public class CartesianCanvas : Canvas
{
    public CartesianCanvas()
    {
        LayoutTransform = new ScaleTransform() { ScaleX = 1, ScaleY = -1 };
    }
    protected override Size ArrangeOverride( Size arrangeSize )
    {
        Point middle = new Point( arrangeSize.Width / 2, arrangeSize.Height / 2 );

        foreach( UIElement element in base.InternalChildren )
        {
            if( element == null )
            {
                continue;
            }
            double x = 0.0;
            double y = 0.0;
            double left = GetLeft( element );
            if( !double.IsNaN( left ) )
            {
                x = left;
            }

            double top = GetTop( element );
            if( !double.IsNaN( top ) )
            {
                y = top;
            }

            element.Arrange( new Rect( new Point( middle.X + x, middle.Y + y ), element.DesiredSize ) );
        }
        return arrangeSize;
    }
}
Run Code Online (Sandbox Code Playgroud)


per*_*ife 6

您只需更改原点即可RenderTransformOrigin.

    <Canvas Width="Auto" Height="Auto"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            RenderTransformOrigin="0.5,0.5">
        <Canvas.RenderTransform>
            <TransformGroup>
                <ScaleTransform ScaleY="-1" ScaleX="1" />
            </TransformGroup>
        </Canvas.RenderTransform>
    </Canvas>
Run Code Online (Sandbox Code Playgroud)


Job*_*Joy 5

最好的方法是编写一个自定义Canvas,您可以在其中编写ArrangeOverride,以0,0为中心.

更新:我在下面的答案中给出了另一个评论(@decasteljau)我不推荐从Canvas派生,你可以从Panel派生并添加两个Attached Dependancy属性Top和Left并将你粘贴的相同代码放在上面.也不需要一个带有LayoutTransform的构造函数,并且不要在面板代码上使用任何变换使用适当的度量并根据面板的DesiredSize进行排列这样你就可以获得不错的内容调整大小行为.当画布大小更改时,画布不会动态定位项目.

  • @JobiJoy,您能提供描述的任何示例实现吗? (3认同)