.net - WPF MVVM拖放

标签 .net wpf mvvm drag-and-drop adorner

我有一个使用拖放功能的应用程序。我已经根据MVVM概念使用行为实现了此功能。我尝试使用adorner元素来创建移动对象的错觉。但是我得到了一个非常奇怪的行为。似乎渲染引擎为其添加了一些偏移,因此它未出现在所需位置。并看起来像偏移量累积。我已经附加了示例项目,因此该问题很容易重现。

private void AssociatedObjectOnMouseMove(object sender, MouseEventArgs mouseEventArgs)
    {
        Point currentPosition = mouseEventArgs.GetPosition(RelativeElement);

        //Point currentPosition = mouseEventArgs.GetPosition(Window.GetWindow(this.AssociatedObject));
        if (!_isMousePressed || !this.AssociatedObject.IsMouseOver)
            return;

        if (Math.Abs(_originalPosition.X - currentPosition.X) < SystemParameters.MinimumHorizontalDragDistance &&
            Math.Abs(_originalPosition.Y - currentPosition.Y) < SystemParameters.MinimumVerticalDragDistance)
            return;

        IDragable context = this.AssociatedObject.DataContext as IDragable;
        if (context == null)
            return;


        Debug.WriteLine("Mouse leave");
        _adorner = new DefaultAdorner(this.AssociatedObject, new Point(0, 0), RelativeElement);

        DataObject data = new DataObject();
        data.SetData(context.DataType, context);
        System.Windows.DragDrop.DoDragDrop(this.AssociatedObject, data, DragDropEffects.Move);

        if (_adorner != null)
        {
            _adorner.Destroy();
            _adorner = null;
        }

        _isMousePressed = false;
    }


    private void AssociatedObjectOnGiveFeedback(object sender, GiveFeedbackEventArgs giveFeedbackEventArgs)
    {
        Debug.WriteLine("feedback");
        Point mouseCoordinates = Extensions.GetMouseCoordinates();
        //Debug.WriteLine("initial x: {0}; y: {1}", mouseCoordinates.X, mouseCoordinates.Y);
        Point mousePosition = RelativeElement.PointFromScreen(mouseCoordinates);

        AdornerLayer layer = AdornerLayer.GetAdornerLayer(this.AssociatedObject);
        var relative = RelativeElement.TranslatePoint(mousePosition, layer);
        Debug.WriteLine("relative to layer x: {0}; y: {1}", relative.X, relative.Y);
        var towindow = RelativeElement.TranslatePoint(mousePosition, Window.GetWindow(this.AssociatedObject));
        Debug.WriteLine("relative to layer x: {0}; y: {1}", towindow.X, towindow.Y);
        //Point mousePosition = Window.GetWindow(this.AssociatedObject).PointFromScreen(Extensions.GetMouseCoordinates());
        if (_adorner != null)
        {
            _adorner.SetMousePosition(mousePosition);
        }
    }

/// <summary>
    /// Create an adorner.
    /// The created adorner must then be added to the AdornerLayer.
    /// </summary>
    /// <param name="adornedElement">Element whose AdornerLayer will be use for displaying the adorner</param>
    /// <param name="adornerElement">Element used as adorner</param>
    /// <param name="adornerOrigin">Origin offset within the adorner</param>
    /// <param name="opacity">Adorner's opacity</param>
    public DefaultAdorner(UIElement adornedElement, Point origin, FrameworkElement relative)
        : base(adornedElement)
    {
        Rectangle rect = new Rectangle();
        rect.Width = adornedElement.RenderSize.Width;
        rect.Height = adornedElement.RenderSize.Height;

        VisualBrush visualBrush = new VisualBrush(adornedElement);
        visualBrush.Opacity = 0.5;
        visualBrush.Stretch = Stretch.None;
        rect.Fill = visualBrush;


        this._child = rect;

        this._adornerOrigin = new Point(0, 0);

        this._adornerOffset = origin;
        _relative = relative;
        AdornerLayer layer = AdornerLayer.GetAdornerLayer(adornedElement);

        Adorner[] adorners = layer.GetAdorners(adornedElement);
        if (adorners != null)
        {
            Array.ForEach(adorners, layer.Remove);   
        }

        layer.Add(this);
        InvalidateVisual();
    }

    /// <summary>
    /// Set the position of and redraw the adorner.
    /// Call when the mouse cursor position changes.
    /// </summary>
    /// <param name="position">Adorner's new position relative to AdornerLayer origin</param>
    public void SetMousePosition(Point position)
    {
        this._adornerOffset.X = position.X;
        this._adornerOffset.Y = position.Y;



        Debug.WriteLine("x: {0}; y: {1}", position.X, position.Y);
        Debug.WriteLine("x: {0}; y: {1}", position.X, position.Y);
        //this._adornerOffset.X = position.X - this._adornerOrigin.X - _child.Width / 2;
        //this._adornerOffset.Y = position.Y - this._adornerOrigin.Y - _child.Height / 2;
        UpdatePosition();
    }

    private void UpdatePosition()
    {
        AdornerLayer adornerLayer = (AdornerLayer)this.Parent;
        if (adornerLayer != null)
        {
            adornerLayer.Update(this.AdornedElement);
        }
        //AdornerLayer.GetAdornerLayer(AdornedElement).Update();
    }

    protected override int VisualChildrenCount { get { return 1; } }

    protected override Visual GetVisualChild(int index)
    {
        System.Diagnostics.Debug.Assert(index == 0, "Index must be 0, there's only one child");
        return this._child;
    }

    protected override Size MeasureOverride(Size finalSize)
    {
        this._child.Measure(finalSize);
        return this._child.DesiredSize;
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        this._child.Arrange(new Rect(finalSize));
        return finalSize;
    }

    public override GeneralTransform GetDesiredTransform(GeneralTransform transform)
    {
        Debug.WriteLine(transform);

        GeneralTransformGroup newTransform = new GeneralTransformGroup();
        MatrixTransform tr = transform as MatrixTransform;
        if (tr != null)
        {
            //newTransform.Children.Add(base.GetDesiredTransform(new MatrixTransform(new Matrix(tr.Matrix.M11, tr.Matrix.M12, tr.Matrix.M21, tr.Matrix.M22, 0, 0))));
            //newTransform.Children.Add(base.GetDesiredTransform(new MatrixTransform(new Matrix(tr.Matrix.M11, tr.Matrix.M12, tr.Matrix.M21, tr.Matrix.M22, this._adornerOffset.X, this._adornerOffset.Y))));
        }

        newTransform.Children.Add(base.GetDesiredTransform(transform));
        newTransform.Children.Add(new TranslateTransform(this._adornerOffset.X, this._adornerOffset.Y));
        return newTransform;
    }

    public void Destroy()
    {
        AdornerLayer.GetAdornerLayer(AdornedElement).Remove(this);
    }

感谢任何帮助!
这是项目的链接:https://www.dropbox.com/s/nogt3gjwmf5e3pg/SandBox.zip?dl=0

最佳答案

试试这个<sandBox:DragBehavior RelativeElement="{Binding ElementName=Label}"/>代替<sandBox:DragBehavior RelativeElement="{Binding ElementName=Canvas}"/>

关于.net - WPF MVVM拖放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32312145/

相关文章:

c# - 在 MVVM 应用程序中存储应用程序设置/状态的位置

mvvm - 命名空间 MvvmCross.Forms 中不存在类型或命名空间平台

c# - 无法使转换器工作

.net - 在 Windows 应用程序中格式化标签内的文本

wpf - 如何使用 MVVM 在 ListView 中设置特定项目?

wpf - MVVM 和分层,实现服务层

c# - 回避异常和 "a function evaluation has timed out"

c# - 如何为 64 位应用程序注册 .NET DLL

.net - 黑名单送货地址逻辑

c# - 使用 Reflection.Emit 动态创建针对特定 .NET 运行时的程序集