WPF:如何使 (0,0) 位于画布中心

发布于 2024-08-14 05:16:22 字数 527 浏览 2 评论 0原文

WPF Canvas 有一个坐标系,从控件左上角的 (0,0) 开始。

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

<Control Canvas.Left="0" Canvas.Top="0">

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

基本上:

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

我注意到这篇文章 类似,但它没有讨论转换坐标系。我尝试添加 TranslateTransform,但无法使其工作。

The WPF Canvas has a coordinate system starting at (0,0) at the top-left of the control.

For example, setting the following will make my control appear on the top-left:

<Control Canvas.Left="0" Canvas.Top="0">

How can I change it to the standard cartesian coordinates?

Basically:

  • (0,0) at center
  • flip Y

I noticed this post is similar, but it does not talk about translating the coordinate system. I tried adding a TranslateTransform, but I can't make it work.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

鹿港小镇 2024-08-21 05:16:22

无需创建自定义面板。Canvas 就可以了。只需将其包裹在另一个控件(例如边框)内,将其居中,将其大小设置为零,然后使用 RenderTransform 翻转它:

<Border>
  <Canvas HorizontalAlignment="Center" VerticalAlignment="Center"
          Width="0" Height="0"
          RenderTransform="1 0 0 -1 0 0">
    ...
  </Canvas>
</Border>

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

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

There is no need to create a custom Panel. Canvas will do just fine. Simply wrap it inside another control (such as a border), center it, give it zero size, and flip it with a RenderTransform:

<Border>
  <Canvas HorizontalAlignment="Center" VerticalAlignment="Center"
          Width="0" Height="0"
          RenderTransform="1 0 0 -1 0 0">
    ...
  </Canvas>
</Border>

You can do this and everything in the canvas will still appear, except (0,0) will be at the center of the containing control (in this case, the center of the Border) and +Y will be up instead of down.

Again, there is no need to create a custom panel for this.

顾挽 2024-08-21 05:16:22

这很容易做到。我使用 .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;
    }
}

It was very easy to do. I looked at the original Canvas's code using .NET Reflector, and noticed the implementation is actually very simple. The only thing required was to override the function 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;
    }
}
哀由 2024-08-21 05:16:22

您只需使用 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>

You can simply change the Origin with 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>
停滞 2024-08-21 05:16:22

最好的就是写一个自定义的Canvas,在里面可以这样写ArrangeOverride,以0,0为中心。

更新:我在下面的答案中给出了另一条评论(@decasteljau),我不建议从 Canvas 派生,您可以从 Panel 派生并添加两个附加依赖属性“顶部”和“左侧”,并放置与上面粘贴的相同代码。也不需要带有 LayoutTransform 的构造函数,并且不要在面板代码上使用任何转换,使用适当的测量并根据面板的 DesiredSize 进行排列,这样您也可以获得良好的内容调整大小行为。当 Canvas 大小发生变化时,Canvas 不会动态定位项目。

The best thing is to write a custom Canvas, in which you can write ArrangeOverride in such a way that it takes 0,0 as the center.

Update : I had given another comment in the below answer (@decasteljau) I wont recommend deriving from Canvas, You can derive from Panel and add two Attached Dependancy properties Top and Left and put the same code you pasted above. Also doesnt need a constructor with LayoutTransform in it, And dont use any transform on the panel code use proper measure and arrange based on the DesiredSize of the panel So that you can get nice content resize behavior too. Canvas doesn't dynamically position items when the Canvas size changes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文