博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[转载]WPF控件拖动
阅读量:7086 次
发布时间:2019-06-28

本文共 12536 字,大约阅读时间需要 41 分钟。

这篇博文总结下WPF中的拖动,文章内容主要包括:

1.拖动窗口

2.拖动控件 Using Visual Studio

  2.1thumb控件

  2.2Drag、Drop(不连续,没有中间动画)

  2.3拖动一个控件

  2.4让一个窗口内的所有(指定的)控件可拖动

3.Expression Blend X实现拖动(Best Practice)

小结

1.拖动窗口                        

我们知道,鼠标放在窗口的标题栏上按下就可以拖动窗体。我们要实现在窗口的全部地方或特定地方按下鼠标左键实现拖动。

Winform的做法是,获取鼠标的位置信息,从而设置窗体的位置。

WPF也可以采用Winform类似的方法,但是没有必要,因为有更加单的方法。

有Grid布局的窗口,里面放置了一个Canvas。

要实现在Grid内按下鼠标左键实现窗体拖动/或是Canvas内实现按下鼠标左键实现窗体拖动,代码如下:

private void canvas1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e){   base.DragMove();//实现整个窗口的拖动}private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e){   base.DragMove();}

从上面的代码我们可以看到,DragMove()方法仅用来实现窗体的拖动。

2.拖动控件               

 2.1thumb控件

thumb控件MSDN的描述非常简单:Represents a control that can be dragged by the user.(表示可由用户拖动的控件)。

由DragStarted、DragDelta、DragCompleted着三个事件完成控件的拖动。

给个例子:我们在Canvas中加入如下thumb控件

实现相应的事件,即可完成该控件的拖动工作。

private void DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e){   Canvas.SetLeft(thumb1,Canvas.GetLeft(thumb1)+e.HorizontalChange);   Canvas.SetTop(thumb1, Canvas.GetTop(thumb1) + e.VerticalChange);}private void DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e){   thumb1.Background = Brushes.White;}private void DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e){   thumb1.Background = Brushes.Red;}

这只是一个简单的示例,我们知道thumb有拇指的意思,代表着很棒的意思。

在2008-08-23在codeproject上发表的(WPF图形设计器)系列文章(共3篇),被国内很多人Copy过来说是他自己弄的(吐槽:这里省去3K字),其中关于thumb的运用可供参考,thumb可以实现控件的拖动。

2.2 drag、drop(不连续,没有中间动画)

很多控件都有AllowDrop属性:允许放下;和Drop事件。

给出两个例子。

例1:

现在,拖拽label1到label上,把label1的text赋值给label2.实现如下:

private void label1_MouseDown(object sender, MouseButtonEventArgs e){    Label lbl = (Label)sender;    DragDrop.DoDragDrop(lbl, lbl.Content, DragDropEffects.Copy);}private void tagert_drop(object sender, DragEventArgs e){    ((Label)sender).Content = e.Data.GetData(DataFormats.Text);}

例2:

 界面上有两个Canvas,右面的Canvas里面有一个Rectangle。拖动右面的Rectangle把它拖到左边来,并且保留右边的Rectangle。 

namespace WpfApplicationDrugMove{    ///     /// Interaction logic for Windowdragdrop.xaml    ///     public partial class Windowdragdrop : Window    {        public Windowdragdrop()        {            InitializeComponent();            canvas1.AllowDrop = true;            rectangle1.PreviewMouseMove += new MouseEventHandler(rectangle1_PreviewMouseMove);            canvas1.DragOver += new DragEventHandler(canvas1_DragOver);            canvas1.Drop += new DragEventHandler(canvas1_Drop);        }             void rectangle1_PreviewMouseMove(object sender, MouseEventArgs e)        {            if (e.LeftButton == MouseButtonState.Pressed)            {                DataObject data = new DataObject(typeof(Rectangle), rectangle1);                DragDrop.DoDragDrop(rectangle1, data, DragDropEffects.Copy);            }        }        void canvas1_Drop(object sender, DragEventArgs e)        {            IDataObject data = new DataObject();            data = e.Data;            if (data.GetDataPresent(typeof(Rectangle)))            {                Rectangle rect = new Rectangle();                rect = data.GetData(typeof(Rectangle)) as Rectangle;                //canvas2.Children.Remove(rect);                //canvas1.Children.Add(rect);                //序列化Control,以深复制Control!!!!                string rectXaml = XamlWriter.Save(rect);                StringReader stringReader = new StringReader(rectXaml);                XmlReader xmlReader = XmlReader.Create(stringReader);                UIElement clonedChild = (UIElement)XamlReader.Load(xmlReader);                canvas1.Children.Add(clonedChild);            }        }               void canvas1_DragOver(object sender, DragEventArgs e)        {            if(!e.Data.GetDataPresent(typeof(Rectangle)))            {                e.Effects = DragDropEffects.None;                e.Handled = true;            }                    }    }}

效果如下:

 这个也就回答了博客园的一篇博问:

 虽然这个问题被标记为解决,但是其解决的方法过于丑陋,具体请看DebugLZQ本文代码实现。

 2.3拖动一个控件

 实现和thumb一样的效果,不同于drag/drop,拖动的时候控件跟随鼠标移动。

Canvas中又一个控件(Canvas2),实现canvas2的拖动。

实现canvas2的MouseLeftButtonDown、MouseMove、MouseLeftButtonUp事件。

Point oldPoint = new Point();bool isMove = false;private void canvas2_MouseMove(object sender, MouseEventArgs e){   if (isMove)   {       canvas2.Background = Brushes.White;       FrameworkElement currEle = sender as FrameworkElement;       double xPos = e.GetPosition(null).X - oldPoint.X + (double)currEle.GetValue(Canvas.LeftProperty);       double yPos = e.GetPosition(null).Y - oldPoint.Y + (double)currEle.GetValue(Canvas.TopProperty);       currEle.SetValue(Canvas.LeftProperty, xPos);       currEle.SetValue(Canvas.TopProperty, yPos);                       oldPoint = e.GetPosition(null);   }}private void canvas2_MouseDown(object sender, MouseButtonEventArgs e){   isMove = true;   oldPoint = e.GetPosition(null);}private void canvas2_MouseLeftButtonUp(object sender, MouseButtonEventArgs e){   isMove = false;   canvas2.Background = Brushes.Yellow;}

 2.4让一个窗口内的所有(指定的)控件可拖动

有2.3的基础,现在我们就可以很方便的实现容器内所有控件拖动了。不仅仅局限于Canvas。其实Canvas的绝对定位和其他的容器(如Grid)没多好差别,只不过Canvas使用Left/Top来定位;Grid是用Margin,仅此而已!

1.还是Canvas中的拖动

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Windows;using System.Windows.Controls;using System.Windows.Data;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Imaging;using System.Windows.Shapes;namespace WpfApplicationDrugMove{    ///     /// Interaction logic for WindowWPFALLControlDrag.xaml    ///     public partial class WindowWPFALLControlDragInCanvas:Window    {        public WindowWPFALLControlDragInCanvas()        {            InitializeComponent();            foreach (UIElement uiEle in LayoutRoot.Children)            {                //WPF设计上的问题,Button.Clicked事件Supress掉了Mouse.MouseLeftButtonDown附加事件等.                //不加这个Button、TextBox等无法拖动                if (uiEle is Button||uiEle is TextBox)                {                    uiEle.AddHandler(Button.MouseLeftButtonDownEvent, new MouseButtonEventHandler(Element_MouseLeftButtonDown), true);                    uiEle.AddHandler(Button.MouseMoveEvent, new MouseEventHandler(Element_MouseMove),true);                    uiEle.AddHandler(Button.MouseLeftButtonUpEvent, new MouseButtonEventHandler(Element_MouseLeftButtonUp), true);                    continue;                }                //                uiEle.MouseMove += new MouseEventHandler(Element_MouseMove);                uiEle.MouseLeftButtonDown += new MouseButtonEventHandler(Element_MouseLeftButtonDown);                uiEle.MouseLeftButtonUp += new MouseButtonEventHandler(Element_MouseLeftButtonUp);                            }                 }        bool isDragDropInEffect = false;        Point pos = new Point();        void Element_MouseMove(object sender, MouseEventArgs e)        {            if (isDragDropInEffect)            {                FrameworkElement currEle = sender as FrameworkElement;                double xPos = e.GetPosition(null).X - pos.X + (double)currEle.GetValue(Canvas.LeftProperty);                double yPos = e.GetPosition(null).Y - pos.Y + (double)currEle.GetValue(Canvas.TopProperty);                currEle.SetValue(Canvas.LeftProperty, xPos);                currEle.SetValue(Canvas.TopProperty, yPos);                pos = e.GetPosition(null);            }        }         void Element_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)        {                        FrameworkElement fEle = sender as FrameworkElement;            isDragDropInEffect = true;            pos = e.GetPosition(null);            fEle.CaptureMouse();            fEle.Cursor = Cursors.Hand;        }        void Element_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)        {            if (isDragDropInEffect)            {                FrameworkElement ele = sender as FrameworkElement;                isDragDropInEffect = false;                ele.ReleaseMouseCapture();            }        }     }}

注意:需要用AddHandler添加Button.MouseLeftButtonDown等事件,不然无法触发,因为Button.Clicked事件Supress掉了MouseLeftButtonDown。

这样页面上的所有控件就可以随意拖动了。

今天在CodeProject上看到了这篇文章:,说的是一个事情。

2.Canvas换成Grid。Grid中所有控件可拖动。

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Windows;using System.Windows.Controls;using System.Windows.Data;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Imaging;using System.Windows.Shapes;namespace WpfApplicationDrugMove{    ///     /// Interaction logic for WindowWPFALLControlDragMoveInGrid.xaml    ///     public partial class WindowWPFALLControlDragMoveInGrid : Window    {        public WindowWPFALLControlDragMoveInGrid()        {            InitializeComponent();            foreach (UIElement uiEle in LayoutRoot.Children)            {                if (uiEle is Button || uiEle is TextBox)                {                    uiEle.AddHandler(Button.MouseLeftButtonDownEvent, new MouseButtonEventHandler(Element_MouseLeftButtonDown), true);                    uiEle.AddHandler(Button.MouseMoveEvent, new MouseEventHandler(Element_MouseMove), true);                    uiEle.AddHandler(Button.MouseLeftButtonUpEvent, new MouseButtonEventHandler(Element_MouseLeftButtonUp), true);                    continue;                }                uiEle.MouseMove += new MouseEventHandler(Element_MouseMove);                uiEle.MouseLeftButtonDown += new MouseButtonEventHandler(Element_MouseLeftButtonDown);                uiEle.MouseLeftButtonUp += new MouseButtonEventHandler(Element_MouseLeftButtonUp);            }         }        bool isDragDropInEffect = false;        Point pos = new Point();        void Element_MouseMove(object sender, MouseEventArgs e)        {            if (isDragDropInEffect)            {                FrameworkElement currEle = sender as FrameworkElement;                double xPos = e.GetPosition(null).X - pos.X + currEle.Margin.Left;                double yPos = e.GetPosition(null).Y - pos.Y + currEle.Margin.Top;                currEle.Margin = new Thickness(xPos, yPos, 0, 0);                pos = e.GetPosition(null);            }        }        void Element_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)        {            FrameworkElement fEle = sender as FrameworkElement;            isDragDropInEffect = true;            pos = e.GetPosition(null);            fEle.CaptureMouse();            fEle.Cursor = Cursors.Hand;        }        void Element_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)        {            if (isDragDropInEffect)            {                FrameworkElement ele = sender as FrameworkElement;                isDragDropInEffect = false;                ele.ReleaseMouseCapture();            }        }     }}

效果如下:

 Grid界面中的所有控件可随意拖动。

3.使用Expression Blend实现拖动(Best Practice)

使用如下的一个Behavior:MouseDragElementBehavior

实现方法非常简单,let's say 我们有个Rectangle,无论在什么容器中,我们要实现其拖动。

直接把这个MouseDragElementBehavior 拖动到Rectangle中即可。

XAML如下:

(如您所见,DebugLZQ使用的是 Expression Blend 4)。

程序运行正常,Rectangle可随意拖动如下:

使用Blend借助Behaviors不需要额外的C#代码,最为简洁。

其他的一些Behaviors也非常有用,

如播放MP3:

程序可正常运行。

还有如CallMethodAction,ControlStoryboardAction,及MVVM中使用较多的InvokeCommandAction等。

 小结一下:

关于2.2例2中控件的序列化、反序列化! 参考:

关于Button.MouseLeftButtonDown用C#代码注册的话需要用AddHandler添加,直接添加会被Button.Clicked阻止! 另一种情况是:我们如何捕获一个路由事件,即使这个路由事件已经被标记为e.handled=true。这个很重要!!!参考:  。拖动不局限于Canvas. 

所有方法中,Blend实现最为Clearn.关于Blend 4的快捷键,请参考:

 

老鸟绕过,轻拍~

Wish it helps. 

虽功未成,亦未敢藏私,众侠诸神通尽录于此,竟成一笈,名葵花宝典,以飨后世。 
邮箱:steven9801@163.com 
QQ: 48039387

转载地址:http://ongml.baihongyu.com/

你可能感兴趣的文章
模板方法模式(Template Method)
查看>>
创建预编译头 Debug 正常 Release Link Error:预编译头已存在,使用第一个 PCH
查看>>
asp.net上传文件夹权限配置以及权限配置的分析
查看>>
IPC's epoch 6 is less than the last promised epoch 7
查看>>
C语言 · 寂寞的数
查看>>
android Menu 笔记
查看>>
Apache2.2和Apache2.4中httpd.conf配置文件 权限的异同
查看>>
error:Flash Download failed-“Cortex-M3”,“Programming Algorithm”【转】
查看>>
小tips:JS之break,continue和return这三个语句的用法
查看>>
【Java】Java_09 类型转换
查看>>
AndroidStudio gradle配置
查看>>
poj3067 Japan(树状数组)
查看>>
Nvidia驱动正确安装过程
查看>>
双节点weblogic集群安装
查看>>
【HDU 2586】LCA模板
查看>>
[java面试]关于多态性的理解
查看>>
Hibernate核心类和接口具体介绍
查看>>
常见的MIME类型
查看>>
Leetcode_Wildcard Matching
查看>>
docker 私有仓库简易搭建
查看>>