拖拽操作其实与剪切与粘贴没有什么不同,只不过是它是使用鼠标而不是键盘,在两类操作中,都会有一个来源(被拖拽、被剪切的文字)和目标(拖往的、被粘贴的位置)。无论哪种操作,都会在内存中存在数据的一份副本,在剪切操作中会使用到剪切板,而在拖拽操作中,会使用到DataObject对象,这个DataObject对象就好比是一个私有的剪切板
在应用程序中,是通过一系列事件,如DragEnter,DragLeave和DragDrop事件来实现在Windows应用程序中的拖拽操作。
注意:只有当控件的
AllowDrag
属性为true时才能拖拽AllowDrop属性被设定成True的任何控件都可以是置放目标。您可以在设计阶段在“属性”窗口中将要作为目标控件的AllowDrop属性设定成True,或者是于运行阶段在窗体的Load事件处理函数中将要作为目标控件的AllowDrop属性设定成True。
拖放操作在代码中是通过三步实现的:
-
首先是启动拖放操作,在需要拖动数据的控件上实现MouseDown事件的响应代码,并调用DoDragDrop方法实现
MouseDown
:当鼠标指针落在组件上方,并按下鼠标按钮时发生关于
DoDragDrop
方法,在类库中的定义为:public DragDropEffects DoDragDrop(object data, DragDropEffects allowedEffects);
其中data参数为要拖放的数据,allowedEffects表示要拖放的效果,可以是复制、拖放、链接等效果,
DragDropEffects
是枚举值,具体为public enum DragDropEffects { Scroll=int.MinValue, All=-2147483645, None=0, // 拖放目标不接受数据 Copy=1, // 拖放源中的数据复制到放置目标 Move=2, // 拖放源中的数据拖到放置目标 Link=4; // 拖动源中的数据链接到放置目标 }
当开始调用DoDragDrop方法拖动一个数据对象时,DoDragDrops在拖放过程中,检测当前光标位置下的控件是不是有效的放置目标。如果当前光标下的控件是有效的放置目标,则GiveFeedBack事件以指定的拖放效果引发。在检测当前位置光标是否为有效的拖放目标时,DoDragDrops方法同时跟踪光标位置,键盘状态和鼠标状态的更改。
-
如果用于移出了一个窗口,则引发DragLeave事件
-
如果移入了一个控件,则引发该控件的DragEnter事件
-
如果鼠标移动,但是停留在一个控件中,则引发DragOver事件
-
如果用一个有效的置放目标上放开鼠标按键,将会引发目标控件的DragDrop事件
如果检测到更改了键盘或者鼠标状态,则引发拖放源的QueryContinueDrag事件, 并根据事件的QueryContinueDragEventArgs的Action属性值确定继续拖动,放置数据或取消操作
-
如果Action属性指定为Continue,则将引发DragOver事件
-
如果Action属性指定为Drop,则将放置效果返回给源,以便应用程序对数据进行适当的操作;例如,如果是移动操作,则剪切数据
-
如果是DragAction的值为Cancel,则引发DragLeave事件
示例代码
private void listBox1_MouseDown(object sender, MouseEventArgs e) { // 如果listBox中的元素为0直接返回 if (listBox1.Items.Count == 0) return; int index = listBox1.SelectedIndex; moveLayerIndex = index; // 如果鼠标点在空白处自己返回 if (index < 0) return; string s = listBox1.Items[index].ToString(); // 调用拖拽实现的方法-在本实验中依次触发DragEnter和DragDrop事件 DragDropEffects dde = DoDragDrop(s, DragDropEffects.Move); // 如果是拖到上面,那么原来的位置为下移一层要删除,拖到下面,位置不变 if (s == listBox1.Items[index].ToString()) listBox1.Items.RemoveAt(index); else listBox1.Items.RemoveAt(index + 1); }
-
-
实现拖放效果-DragEnter,使用DragDropEffects枚举类型实现移动或复制等拖动效果
通常我们会在使用
GetDataPresent
方法去检测所拖曳的数据格式是否适用于目标控件,并使用DragEventArgs类型参数的Effect属性来设定所允许的置放操作示例代码
private void listBox1_DragEnter(object sender, DragEventArgs e) { //使用GetDataPresent方法来检查被拖曳的数据是否为纯文字(DataFormats.Text) //是的话将e.Effect属性设定为Move,否则设定为None表示不接受该数据 if (e.Data.GetDataPresent(DataFormats.Text)) e.Effect = DragDropEffects.Move; else e.Effect = DragDropEffects.None; }
-
实现放置数据操作,在目标控件上添加DragDrop响应代码,把数据添加到目标控件中
也要先用
GetDataPresent
检查下数据源是不是字符串DataFormats.StringFormat
,是的话执行后续的拖入操作中间的过程实现的是基于Arcgis Engine图层的拖拽效果,大家可以根据不同的需求完成
示例代码
private void listBox1_DragDrop(object sender, DragEventArgs e) { if(e.Data.GetDataPresent(DataFormats.StringFormat)) { System.Drawing.Point point = listBox1.PointToClient(new System.Drawing.Point(e.X, e.Y)); int index = listBox1.IndexFromPoint(point); if (index > -1) { MessageBox.Show("你将把" + e.Data.GetData(DataFormats.StringFormat) + "图层移动到" + listBox1.Items[index] + "之上"); listBox1.Items.Insert(index, listBox1.SelectedItem); // Insert是插在index之上 axMapControl1.MoveLayerTo(moveLayerIndex, index); } else { MessageBox.Show("你将把" + e.Data.GetData(DataFormats.StringFormat) + "图层移动到最底层"); listBox1.Items.Add(listBox1.SelectedItem); axMapControl1.MoveLayerTo(moveLayerIndex, axMapControl1.LayerCount-1); } } }