将TranslateTranform应用于我的画布是非常容易的WPF

时间:2019-05-14 12:38:09

标签: wpf canvas transform

我正在尝试使用附加属性将“平移”变换应用于我的Canvas-画布在拖动时会移动,但跳动性很强,并试图不断跳回到原始位置。当我滚动出画布时,它也会完全混乱,并将画布拖离屏幕。

我附加的属性类方法:


private Point _originalMouseDownPoint;


 private void AssociatedObjectOnMouseMove(object sender, MouseEventArgs mouseEventArgs) {
            var pos = mouseEventArgs.GetPosition(AssociatedObject);
            MouseX = pos.X;
            MouseY = pos.Y;
            var canvas = sender as Canvas;
            if (BaseViewModel.Mode != MouseHandlingModeEnum.Panning) return;
            var translateTransform = new
                TranslateTransform(pos.X - _originalMouseDownPoint.X, pos.Y - _originalMouseDownPoint.Y);

            canvas.RenderTransform = translateTransform;
        }

        private void AssociatedObjectOnMouseDown(object sender, MouseButtonEventArgs e) {
            var canvas = sender as Canvas;
            canvas.CaptureMouse();
            canvas.Focus();
            _originalMouseDownPoint = e.GetPosition(canvas);
            BaseViewModel.Mode = MouseHandlingModeEnum.Panning;
        }

private void AssociatedObjectOnMouseUp(object sender, MouseButtonEventArgs e) {
            var canvas = sender as Canvas;
            canvas.ReleaseMouseCapture();
            BaseViewModel.Mode = MouseHandlingModeEnum.None;
        }

然后我的XAML只是通过画布行为来进行设置。

<i:Interaction.Behaviors>
                    <attachedProperties:MouseBehaviour  MouseX="{Binding PanelX , Mode=OneWayToSource}"
                                           MouseY="{Binding PanelY, Mode=OneWayToSource}" />

                    </i:Interaction.Behaviors>

(忽略绑定,它们是单独的功能。

程序应在画布上平移。我见过有人使用矩阵变换,是否应该尝试以某种方式实现它?

2 个答案:

答案 0 :(得分:0)

根据我的经验,当我只需要以简单的方式拖动或移动对象时,我喜欢使用Canvas.Left / Top。当我做更复杂的事情时(很少见),我会使用转换。通常,它更容易调试和简化。 您可以执行以下操作:

private void AssociatedObjectOnMouseMove(object sender, MouseEventArgs mouseEventArgs) {
        var pos = mouseEventArgs.GetPosition(AssociatedObject);
        MouseX = pos.X;
        MouseY = pos.Y;
        var canvas = sender as Canvas;
        if (BaseViewModel.Mode != MouseHandlingModeEnum.Panning) return;

           Canvas.SetLeft(AssociatedObject, MouseX - _originalMouseDownPoint.X);
           Canvas.SetTop(AssociatedObject, MouseY - _originalMouseDownPoint.Y);
    }

    private void AssociatedObjectOnMouseDown(object sender, MouseButtonEventArgs e) {
        var canvas = sender as Canvas;
        canvas.CaptureMouse();
        canvas.Focus();
        _originalMouseDownPoint = e.GetPosition((UIElement)sender);
        BaseViewModel.Mode = MouseHandlingModeEnum.Panning;
    }

private void AssociatedObjectOnMouseUp(object sender, MouseButtonEventArgs e) {
        var canvas = sender as Canvas;
        canvas.ReleaseMouseCapture();
        _originalMouseDownPoint = null;
        BaseViewModel.Mode = MouseHandlingModeEnum.None;
    }

我假设您的BaseViewModel.Mode是用于指示拖动条件的标志。

如果要将VM绑定到拖动,则可以添加Position属性并直接访问DataContext(var vm = DataContext as AssociatedObjectViewModel)并设置新位置。然后,在XAML中,您可以将Canvas.LeftCanvas.Top绑定到这些属性。但是,这并非总是可能的,这取决于您如何设置所有内容,有时在“隐藏代码”中更轻松/更轻松地解决此问题。

答案 1 :(得分:0)

public class MouseBehaviour : Behavior<Panel> {
    public static readonly DependencyProperty MouseYProperty = DependencyProperty.Register(
        "MouseY", typeof(double), typeof(MouseBehaviour), new PropertyMetadata(default(double)));

    public static readonly DependencyProperty MouseXProperty = DependencyProperty.Register(
        "MouseX", typeof(double), typeof(MouseBehaviour), new PropertyMetadata(default(double)));

    private Point _originalMouseDownPoint;
    private double _hOff = 1;
    private double _vOff = 1;


    public double MouseY {
        get => (double)GetValue(MouseYProperty);
        set => SetValue(MouseYProperty, value);
    }

    public double MouseX {
        get => (double)GetValue(MouseXProperty);
        set => SetValue(MouseXProperty, value);

    }

    protected override void OnAttached() {
        AssociatedObject.MouseUp += AssociatedObjectOnMouseUp;
        AssociatedObject.MouseMove += AssociatedObjectOnMouseMove;
        AssociatedObject.MouseDown += AssociatedObjectOnMouseDown;
    }
    protected override void OnDetaching()
    {
        AssociatedObject.MouseUp -= AssociatedObjectOnMouseUp;
        AssociatedObject.MouseMove -= AssociatedObjectOnMouseMove;
        AssociatedObject.MouseDown -= AssociatedObjectOnMouseDown;

    }
    /// <summary>
    /// Deals with mouse movement event
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="mouseEventArgs"></param>oop
    private void AssociatedObjectOnMouseMove(object sender, MouseEventArgs mouseEventArgs) {
        //Keep track of position of mouse on the canvas
        var canvasPosition = mouseEventArgs.GetPosition(AssociatedObject);

        MouseX = canvasPosition.X;
        MouseY = canvasPosition.Y;

        //If we're currently panning
        var canvas = sender as Canvas;
        var scrollViewer = canvas.Parent as ScrollViewer;

        //Position of the scroll viewer
        var scrollPosition = mouseEventArgs.GetPosition(scrollViewer);

        if (BaseViewModel.Mode != MouseHandlingModeEnum.Panning) return;

        //Then update the scroll viewer based on our mouse movement
        scrollViewer.ScrollToHorizontalOffset(
            _hOff + (_originalMouseDownPoint.X - scrollPosition.X));
        scrollViewer.ScrollToVerticalOffset(_vOff + (_originalMouseDownPoint.Y - scrollPosition.Y));




    }
    /// <summary>
    /// Deals with the mouse down event on the canvas
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void AssociatedObjectOnMouseDown(object sender, MouseButtonEventArgs e)
    {
        var canvas = sender as Canvas;
        var scrollViewer = canvas.Parent as ScrollViewer;

        //Gives the current offset of the scroll viewer
        _hOff = scrollViewer.HorizontalOffset;
        _vOff = scrollViewer.VerticalOffset;
        _originalMouseDownPoint = e.GetPosition(scrollViewer);

        BaseViewModel.Mode = MouseHandlingModeEnum.Panning;
        canvas.CaptureMouse();
        canvas.Focus();

    }




    /// <summary>
    /// Deals with mouse up event
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private static void AssociatedObjectOnMouseUp(object sender, MouseButtonEventArgs e)
    {
        var canvas = sender as Canvas;
        canvas.ReleaseMouseCapture();

        BaseViewModel.Mode = MouseHandlingModeEnum.None;
    }
}

对于以后的读者来说,我最终使用了ScrollViewer,将Canvas包裹在Pan画布上,而Pan遍历了Pancan,现在看来它工作得很好。