【问题标题】:WPF - Touch manipulation problem when translate after a rotationWPF - 旋转后平移时的触摸操作问题
【发布时间】:2019-12-11 15:05:56
【问题描述】:

我对通过操纵事件(更准确地说是矩阵)进行对象转换有疑问。

问题:在我的对象(顺便说一句:一个矩形)第一次成功旋转/缩放/平移后,第二次操作(在本例中为平移)将在其新角度的方向上移动对象。 例如,如果在第一次旋转(新角度为 45°)之后我从右到左触摸屏幕,则对象将遵循 45° 对角线路径而不是我绘制的路径。

期望:我希望我的对象完全按照我在屏幕上创建的路径而不管其旋转。

情况:我通过代码在 Canvas 中放置了一个 Rectangle,该矩形具有“IsManipulationEnabled = true”和“RenderTransformOrigin = new Point(.5, .5)”和“mySuperRectangle.ManipulationDelta += Container_ManipulationDelta;”

这是我使用的代码:

    private void Container_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
    {
        try
        {
            if (e.OriginalSource != null)
            {
                Rectangle image = e.OriginalSource as Rectangle;


                Point center = new Point(image.ActualWidth / 2.0, image.ActualHeight / 2.0);
                Matrix imageMatrix = ((MatrixTransform)image.RenderTransform).Matrix;
                center = imageMatrix.Transform(center);

                // Move the Rectangle.
                imageMatrix.Translate(e.DeltaManipulation.Translation.X,
                                            e.DeltaManipulation.Translation.Y);

                // Rotate the Rectangle.
                imageMatrix.RotateAt(e.DeltaManipulation.Rotation,
                                     center.X,
                                     center.Y);

                // Resize the Rectangle. Keep it square 
                // so use only the X value of Scale.
                imageMatrix.ScaleAt(e.DeltaManipulation.Scale.X,
                                    e.DeltaManipulation.Scale.X,
                                    center.X,
                                    center.Y);

                // Apply changes
                image.RenderTransform = new MatrixTransform(imageMatrix);

                Rect containingRect =
                    new Rect(((FrameworkElement)e.ManipulationContainer).RenderSize);

                Rect shapeBounds =
                    image.RenderTransform.TransformBounds(
                        new Rect(image.RenderSize));

                // Check if the rectangle is completely in the window.
                // If it is not and intertia is occuring, stop the manipulation.
                if (e.IsInertial && !containingRect.Contains(shapeBounds))
                {
                    e.Complete();
                }

                e.Handled = true;
            }
        }
        catch (Exception)
        {
           throw;
        }
    }

有什么想法吗?

非常感谢。

【问题讨论】:

    标签: c# wpf manipulationdelta


    【解决方案1】:

    您应该在 Canvas 上处理操作事件,因为操作的原点应该相对于固定的 Canvas,而不是移动的 Rectangle。

    <Canvas IsManipulationEnabled="True"
            ManipulationDelta="CanvasManipulationDelta">
        <Rectangle x:Name="rectangle" Width="200" Height="200" Fill="Red">
            <Rectangle.RenderTransform>
                <MatrixTransform/>
            </Rectangle.RenderTransform>
        </Rectangle>
    </Canvas>
    

    事件处理程序的工作方式如下:

    private void CanvasManipulationDelta(object sender, ManipulationDeltaEventArgs e)
    {
        var transform = (MatrixTransform)rectangle.RenderTransform;
        var matrix = transform.Matrix;
        var center = e.ManipulationOrigin;
        var scale = (e.DeltaManipulation.Scale.X + e.DeltaManipulation.Scale.Y) / 2;
    
        matrix.ScaleAt(scale, scale, center.X, center.Y);
        matrix.RotateAt(e.DeltaManipulation.Rotation, center.X, center.Y);
        matrix.Translate(e.DeltaManipulation.Translation.X, e.DeltaManipulation.Translation.Y);
    
        transform.Matrix = matrix;
    }
    

    【讨论】:

    • 谢谢@Clemens!你帮了我很大的忙!
    【解决方案2】:

    我的最终代码:

    private void CanvasManipulationDelta(object sender, ManipulationDeltaEventArgs e)
    {
        var transform = rectangle.RenderTransform as MatrixTransform;
        var matrix = transform.Matrix;
        Point center = new Point(rectangle.ActualWidth / 2.0, rectangle.ActualHeight / 2.0);
        center = matrix.Transform(center);
    
        matrix.ScaleAt(e.DeltaManipulation.Scale.X , e.DeltaManipulation.Scale.X, center.X, center.Y);
        matrix.RotateAt(e.DeltaManipulation.Rotation, center.X, center.Y);
        matrix.Translate(e.DeltaManipulation.Translation.X, e.DeltaManipulation.Translation.Y);
    
        rectangle.RenderTransform = new MatrixTransform(matrix);
    }
    

    编辑:不要使用as 运算符而不检查null 的结果。在这种情况下,如果 transform 为 null,则创建一个新的 MatrixTransform 并将其分配给 RenderTransform 属性。之后,重用转换并仅更新其 Matrix 属性。

    改进的代码:

    private void CanvasManipulationDelta(object sender, ManipulationDeltaEventArgs e)
    {
        var transform = rectangle.RenderTransform as MatrixTransform;
    
        if (transform == null) // here 
        {
            transform = new MatrixTransform();
            rectangle.RenderTransform = transform;
        }
    
        var matrix = transform.Matrix;
        var center = new Point(rectangle.ActualWidth / 2.0, rectangle.ActualHeight / 2.0);
        center = matrix.Transform(center);
    
        matrix.ScaleAt(e.DeltaManipulation.Scale.X , e.DeltaManipulation.Scale.X, center.X, center.Y);
        matrix.RotateAt(e.DeltaManipulation.Rotation, center.X, center.Y);
        matrix.Translate(e.DeltaManipulation.Translation.X, e.DeltaManipulation.Translation.Y);
    
        transform.Matrix = matrix; // here
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-16
      • 1970-01-01
      • 2011-07-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多