WPF中的Canvas.Left/Canvas.Top在旋转时不是完全正确的坐标,为什么?

4
我有一个奇怪但很大的问题。我正在尝试让用户在画布上移动/旋转一些矩形。我的机制是基于操纵Canvas.Left / Canvas.Top属性进行移动,以及使用RenderTransform.Rotate进行旋转。我只需要对0/90/180/270角度进行旋转。
问题在于,放置在0度旋转上的坐标为0.0的矩形可以正常显示,但是0.0和90度旋转的相同矩形会在其他坐标处显示元素。据我所见,当旋转为0或180时,坐标始终正确,但是在90/270的情况下是错误的。设置的坐标与用户看到的差异与高度和宽度之间的差异有关。
有人遇到过这种问题吗?
谢谢, 丹尼尔
编辑:
当然,这里是一些XAML代码:

    <Canvas 
        Height="500" 
        Width="500"
        Background="Green"

        <Rectangle 
            Canvas.Left="0" 
            Canvas.Top="0"
            Height="50"
            Width="100"
            RenderTransformOrigin="0.5,0.5"
            Fill="Red"

            <Rectangle.RenderTransform>
                <RotateTransform 
                Angle="90"
                />
            </Rectangle.RenderTransform>
        </Rectangle>
        <Rectangle 
            Canvas.Left="0" 
            Canvas.Top="0"
            Height="50"
            Width="100"
            RenderTransformOrigin="0.5,0.5"
            Fill="RoyalBlue"

            <Rectangle.RenderTransform>
                <RotateTransform 
                Angle="0"
                />
            </Rectangle.RenderTransform>
        </Rectangle>
    </Canvas> 
</Grid>

正如你所看到的,蓝色矩形似乎被正确地放置在(0,0),但红色矩形显示在不同的坐标上,即使它仍然返回0,0。

我发现公式如下:

displayPointX = Canvas.Left + height / 2 - width / 2

diaplayPointY = Canvas.Top + height / 2 - width / 2


1
我曾经使用过旋转,它们有时可能会很棘手。不幸的是,我无法想象你在说什么。你能发布XAML文件,这样我就可以在查看器中看到它吗? - Dave
3个回答

3
Daniell,大家告诉你的都是正确的。如果你有一个矩形,并且将原点设置为0.5, 0.5,那么意味着“围绕该对象的质心旋转”,因此,如果你旋转90或270度,当然它看起来会与你看到的完全相同。
如果您想让矩形旋转90度并仍然停留在左上角,则必须先旋转90度,然后沿X和Y轴平移以使角落与0,0对齐,或者您需要围绕不同的中心旋转(如0,0),并且只沿X轴平移。
以下是示例:
<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Canvas Height="500" Width="500" Background="Green">
        <Rectangle Canvas.Left="0" Canvas.Top="0" Height="50" Width="100" RenderTransformOrigin="0.5,0.5" Fill="Red">
            <Rectangle.RenderTransform>
              <TransformGroup>
                <RotateTransform Angle="90" />
                <TranslateTransform X="-25" Y="25" />
              </TransformGroup>
            </Rectangle.RenderTransform>
        </Rectangle>
        <Rectangle Canvas.Left="0" Canvas.Top="0" Height="50" Width="100" RenderTransformOrigin="0.5,0.5" Fill="RoyalBlue">
            <Rectangle.RenderTransform>
                <RotateTransform Angle="0" />
            </Rectangle.RenderTransform>
        </Rectangle>
    </Canvas> 
</Page>

也许最好你解释一下你真正想用这个做什么。而且奇怪的是,你说0和180很好,因为角落与0,0匹配,但是你的形状被旋转了,我们不知道方向的保留对你是否重要。

1
这些矩形实际上是更复杂的容器,而且是的,方向很重要,我需要将容器中的所有内容旋转。问题在于我无法引用画布0.0点来表示容器坐标。您已将平移变换X和Y设置为25,因为25是(H-W)/ 2,但我的矩形可调整大小。也许解决方案是在调整大小时建立对此X和Y的绑定(?) - daniell
好的,很高兴你解决了它。是的,你绝对可以进行数据绑定。我只是为了演示目的而使用数字25和-25。 - Dave

2
您描述的行为发生在以下情况下:
  1. 您的画布不是矩形的,
  2. 您具有“0.5,0.5”的RenderTransformOrigin,并且
  3. 您使用了旋转变换来进行RenderTransform
您看到这种情况的原因是因为一个围绕其中心旋转180度的矩形具有完全相同的边界,但围绕90或270度旋转的矩形则没有。 想象一下一个宽而瘦的矩形旋转,您很容易看到这一点。
当您旋转90或270度时,您的角落不再与容器匹配。
有许多解决方案:
  • 使容器完全正方形
  • 在90和270度旋转时更改画布的大小(翻转宽度和高度)
  • 将缩放变换与RotateTransform组合,以在任何方向上通过w/h缩放画布,并在旋转为90或270度时通过h/w拉伸画布以适应新的矩形
  • 将TranslateTransform添加到RotateTransform中,在旋转为90或270度时通过w-h和h-w移动坐标系
  • 计算新的RenderTransformOrigin,以使角落出现在您想要的位置

1
很遗憾,我无法修改我的对象。它们是用户可调整大小的。用户应该有可能在任何方向上进行调整大小,在特定坐标处放置并旋转他们想要的方式。 - daniell
在这种情况下,您将想要使用我的第四个答案:除了旋转变换之外,添加一个TranslateTransform,使旋转的矩形与其未旋转的自身匹配坐标。 - Ray Burns

1

坐标系发生变化的原因是画布的坐标系随着画布旋转而旋转。

http://msdn.microsoft.com/en-us/library/system.windows.media.rotatetransform.aspx指出:

当您使用RotateTransform时,请注意,该变换会围绕特定对象的点(0,0)旋转坐标系。

假设您正在以正方形的质心为中心旋转,当您顺时针旋转90度(RotateTransform认为是正方向),(0,0)指的是屏幕上的右上角,对于180度,它指的是右下角,对于270度,它指的是左下角,而在0度时,它如预期地指的是左上角。


1
坐标仅在矩形内部更改。矩形本身仍然指向画布的左上角,您可以通过旋转180度来查看此内容,它仍将在左上角显示0,0。 正如我所说,问题仅出现在90/270度。:( - daniell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接