WPF中实现拖动功能和WinForm中实现的功能有所差异,这里简单介绍下WPF中的拖拽的实现逻辑!

实现拖拽功能,主要包含以下几个步骤:

  1. 需要拖入到的控件中,设置 AllowDrop="True"
  2. 需要拖入到的控件中,注册Drop事件,在该事件中,将拖动到该控件中的数据进行处理。获取数据的方法:e.Data.GetData(typeof(MyClass));
  3. 在拖动的控件,注册PreviewMouseMove事件,在该事件中,启动拖拽行为:DragDrop.DoDragDrop。在设置移动的过程中,因为MouseUp事件会在Drag过程中被吞掉,所以PreviewMouseUp事件不会被触发。为了解决拖动时,鼠标移动触发拖拽情况,只需要在PreviewMouseMove事件中加上e.LeftButton == MouseButtonState.Pressed即可。
  4. 如果需要将拖动的对象,跟随鼠标移动,可以将被拖动元素以自定义Adorner的方式,添加到该元素下的AdornerLayer中。将拖动元素以VisualBrush的方式赋值给Adorner。并在GiveFeedback事件中更新坐标位置。

示例代码:


        //定义个自定义的Adorner
        DefaultAdorner adorner;

        //当鼠标拖入到控件中,并释放鼠标时发生
        private void FrameworkElement_Drop(object sender, DragEventArgs e)
        {
            var data = (MyClass)e.Data.GetData(typeof(MyClass));
           //todo:
        }

        //当鼠标按下,开始移动时开始拖拽
        private void FrameworkElement_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {   
                //添加Adorner到AdornerLayer
                adorner = new DefaultAdorner((UIElement)Application.Current.MainWindow.Content,(UIElement)this._dragDropObject.SourceObject,this._dragDropObject.StartPosition);
                System.Windows.Media.Visual visual = Application.Current.MainWindow.Content as Visual;
                AdornerLayer.GetAdornerLayer(visual).Add(this._dragDropObject.DragAdorner);
                //开始拖动
                DragDrop.DoDragDrop(frameworkElement, data, DragDropEffects.Move);               
            }
        }

         private void DragSource_GiveFeedback(object sender, GiveFeedbackEventArgs e)
         {
            //设置移动Adorner的位置
            adorner.SetMousePosition(dragAdorner.AdornedElement.PointFromScreen(point));
         }

    //DefaultAdorner定义
    public class DefaultAdorner : Adorner
    {
        private UIElement _child;
        private Point _adornerOrigin;
        private Point _adornerOffset;

        public DefaultAdorner(UIElement adornedElement, UIElement adornerElement, Point adornerOrigin)
            : this(adornedElement, adornerElement, adornerOrigin, 0.3)
        {
        }

        //将需要拖动的元素附加到Adorner
        public DefaultAdorner(UIElement adornedElement, UIElement adornerElement, Point adornerOrigin, double opacity)
            : base(adornedElement)
        {
            Rectangle rect = new Rectangle();
            rect.Width = adornerElement.RenderSize.Width;
            rect.Height = adornerElement.RenderSize.Height;

            VisualBrush visualBrush = new VisualBrush(adornerElement);
            visualBrush.Opacity = opacity;
            visualBrush.Stretch = Stretch.None;
            rect.Fill = visualBrush;

            this._child = rect;

            this._adornerOrigin = adornerOrigin;
        }

        public void SetMousePosition(Point position) {
            this._adornerOffset.X = position.X - this._adornerOrigin.X;
            this._adornerOffset.Y = position.Y - this._adornerOrigin.Y;
            UpdatePosition();
        }

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

        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) {
            GeneralTransformGroup newTransform = new GeneralTransformGroup();
            newTransform.Children.Add(base.GetDesiredTransform(transform));
            newTransform.Children.Add(new TranslateTransform(this._adornerOffset.X, this._adornerOffset.Y));
            return newTransform;
        }
    }

以上就是拖动功能实现的主题思路,按照以上思路可对拖动操作做一层封装,简化拖动功能实现的复杂度。


本文会经常更新,请阅读原文: https://huchengv5.gitee.io//post/WPF%E6%8B%96%E5%8A%A8%E5%8A%9F%E8%83%BD%E7%9A%84%E5%AE%9E%E7%8E%B0.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

知识共享许可协议 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名胡承(包含链接: https://huchengv5.gitee.io/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系