【问题标题】:Combining RotateTransform and TranslateTransform结合 RotateTransform 和 TranslateTransform
【发布时间】:2012-06-04 17:20:54
【问题描述】:

我正在使用 Thumb 类让用户在画布上拖放图像。当按下右键时,我希望用户能够旋转图像。旋转基于图像的中心。我有以下 XAML 代码

<Grid>

    <Canvas Background="Red" Grid.RowSpan="2" x:Name="canvas" 
        PreviewMouseRightButtonUp="Canvas_MouseUp" 
        PreviewMouseMove="Canvas_MouseMove">

        <UserControl MouseRightButtonDown="Canvas_MouseDown" RenderTransformOrigin="0.5,0.5">

            <Thumb Name="myRoot" DragDelta="myRoot_DragDelta">
                <Thumb.Template>
                    <ControlTemplate>
                        <Grid>

                            <Image Source="/WpfApplication1;component/someImage.png" />

                            <Rectangle Stroke="#FF0061CE" StrokeThickness="1" Width="230" Height="250" />

                        </Grid>
                    </ControlTemplate>
                </Thumb.Template>
            </Thumb>

            <UserControl.RenderTransform>
                <TransformGroup>
                    <RotateTransform x:Name="rotateTransform" />
                    <TranslateTransform x:Name="translateTransform" />
                </TransformGroup>
            </UserControl.RenderTransform>
        </UserControl>

    </Canvas>

</Grid>

还有这段代码

    bool isMouseDown = false;
    Point pos;
    double lastAngle = 0;

    private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
    {
        isMouseDown = true;
        lastAngle = rotateTransform.Angle;
        pos = Mouse.GetPosition(canvas);
    }   

    private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
    {
        isMouseDown = false;
    }

    private void Canvas_MouseMove(object sender, MouseEventArgs e)
    {
        if (!isMouseDown) return;

        var curPos = Mouse.GetPosition(canvas);
        rotateTransform.Angle = lastAngle + (pos.Y - curPos.Y);
    }

    private void myRoot_DragDelta(object sender, DragDeltaEventArgs e)
    {
        translateTransform.X += e.HorizontalChange;
        translateTransform.Y += e.VerticalChange; 
    }

如果我只在屏幕上拖放图像并稍微旋转图像(在任何方向上 50 度似乎都可以),它就可以工作。然而,操作不止于此,图像开始在屏幕上不可预知地移动。

我已经尝试将转换移动到不同的控件,以免混淆它们但没有收到可接受的结果。

我怎样才能让我的代码表现得像我想要的那样?

更新:这让我发疯了。我已更改代码和 XAML 以改用 MatrixTransformation

    private void Canvas_MouseMove(object sender, MouseEventArgs e)
    {
        if (!isMouseDown) return;

        var curPos = Mouse.GetPosition(canvas);

        angle = (lastAngle + (pos.Y - curPos.Y)) % 360;

        UpdateMatrixTransform();
    }

    private void myRoot_DragDelta(object sender, DragDeltaEventArgs e)
    {
        posX += e.HorizontalChange;
        posY += e.VerticalChange;  

        UpdateMatrixTransform();
    }

    void UpdateMatrixTransform()
    {
        Matrix m = new Matrix();


        m.Rotate(angle);

        m.OffsetX = posX;
        m.OffsetY = posY;

        matrixT.Matrix = m;
    }

在我看来,这应该可行:首先,旋转图形而不是将其移动到偏移处。它不像我期望的那样工作。它旋转图像,但如果我继续移动鼠标,它会以螺旋方式奇怪地向外移动。无论我做什么,以什么顺序执行我的转换,它都不会起作用。

【问题讨论】:

  • @Gilad 我不知道这个链接对我有什么帮助,你能给个提示吗?
  • 尝试交换变换的顺序。它应该先平移,然后旋转。
  • @Moozhe 我做了,但是它围绕画布的左上角而不是图像的原点旋转(我将 rendertransformorigin 设置为 0.5,0.5)

标签: c# wpf transform rotatetransform


【解决方案1】:

我不确定您为什么要使用 UserControl 来包装 Thumb,因为它应该能够在此处充当根元素。这是一个解决方案,它取消了使用 TranslateTransform 而是使用 Canvas.Left 和 Canvas.Top 属性:

编辑:更新答案

这是 XAML:

<Canvas x:Name="canvas">
    <Thumb Name="myRoot"
            Canvas.Left="0" Canvas.Top="0"
            DragDelta="myRoot_DragDelta"
            MouseMove="myRoot_MouseMove"
            MouseDown="myRoot_MouseDown"
            MouseUp="myRoot_MouseUp">
        <Thumb.Template>
            <ControlTemplate>
                <Grid RenderTransformOrigin="0.5, 0.5">
                    <Rectangle Fill="AliceBlue"
                               Stroke="#FF0061CE"
                               StrokeThickness="1"
                               Width="100" Height="100"/>
                    <Grid.RenderTransform>
                        <RotateTransform x:Name="rotateTransform" />
                    </Grid.RenderTransform>
                </Grid>
            </ControlTemplate>
        </Thumb.Template>
    </Thumb>
</Canvas>

下面是代码:

public partial class TestWindow : Window
{
    public TestWindow()
    {
        InitializeComponent();
    }

    Point? lastPosition = null;
    RotateTransform rotateTransform;

    private void myRoot_MouseDown(object sender, MouseButtonEventArgs e)
    {
        lastPosition = null;

        if (e.ChangedButton == MouseButton.Right)
            myRoot.CaptureMouse();
    }

    private void myRoot_MouseUp(object sender, MouseButtonEventArgs e)
    {
        if (e.ChangedButton == MouseButton.Right)
            myRoot.ReleaseMouseCapture();
    }

    private void myRoot_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.RightButton == MouseButtonState.Pressed)
        {
            Point curPosition = Mouse.GetPosition(myRoot);

            if (lastPosition != null)
            {
                Point centerPoint = new Point(myRoot.ActualWidth / 2, myRoot.ActualWidth / 2);

                if (rotateTransform == null)
                    rotateTransform = (RotateTransform)myRoot.Template.FindName("rotateTransform", myRoot);

                rotateTransform.Angle = Math.Atan2(curPosition.Y - centerPoint.Y, curPosition.X - centerPoint.X) * 100;
            }

            lastPosition = curPosition;
            e.Handled = true;
        }
    }

    private void myRoot_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
    {
        Canvas.SetLeft(myRoot, Canvas.GetLeft(myRoot) + e.HorizontalChange);
        Canvas.SetTop(myRoot, Canvas.GetTop(myRoot) + e.VerticalChange);
    }
}

【讨论】:

  • 我试过你的代码,虽然旋转部分看起来有点迟钝,但它工作正常,至少在我的机器上它没有像我希望的那样顺利。
  • 这不是理想的方法。我会看看我是否可以写一个更好的例子。
  • 我也看到了与我的版本相同的奇怪行为。一旦旋转超过 90 度,再次拖动时它开始表现怪异(再现:拖动到中间,旋转 180 度,而不是向任何方向拖动)
  • 我想通了。 Thumb 在转换时不会报告正确的增量值。 Thumb 应该高于可视化树中的变换(它的内容可以变换)。我会发布我的代码。
【解决方案2】:

你必须告诉 RotateTransform 你想围绕对象的中心而不是坐标系的中心旋转,这是默认的。为此,请将 RotateTransform 的 CenterX 和 CenterY 属性设置为对象的中心。

【讨论】:

  • 我以为我是通过在 UserControl 上设置 RenderTransformOrigin="0.5,0.5" 来做到这一点的?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-08
  • 2015-10-11
  • 2016-07-11
相关资源
最近更新 更多