2015-08-31 175 views
1

我有一個使用拖放功能的應用程序。我已經根據MVVM的概念,使用行爲實現了這個功能。我試圖使用adorner元素來創建運動對象的幻覺。但是我得到了一個非常奇怪的裝飾行爲。它看起來像渲染引擎添加一些偏移量,所以它不會出現在所需的位置。看起來像偏移積累。我已附加了我的示例項目,因此該問題很容易重現。WPF MVVM拖放

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

+0

這是更好地使用zip壓縮包 - 不是每個人都有一個RAR。 – AntonS

回答

0

試試這個<sandBox:DragBehavior RelativeElement="{Binding ElementName=Label}"/>代替<sandBox:DragBehavior RelativeElement="{Binding ElementName=Canvas}"/>