在VB.NET中实现拖放操作
2024-07-10 13:01:28
供稿:网友
第一次在csdn上发文章,希望大家帮忙使劲顶,鼓励一下新手,谢谢 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vstechart/html/vbtchimpdragdrop.asp 在vb.net中实现拖放操作 implementing drag and drop in visual basic .net steve hoag visual basic® .net team microsoft corporation september 2003 摘要:这篇文章阐述了如何在vb.net中实现拖放操作 绪论 windows用户一般分为两类:一类习惯用键盘操作,一类习惯用鼠标操作。程序员们在编程时一般会提供快捷键(在命令或字母中加下划线)或快捷方式(用ctrl加字母的组合)来照顾到那些习惯键盘的用户,但是那些鼠标用户却被忽略了。因为程序员们一般都习惯用键盘,所以他们这种重视键盘操作的特点是可以理解的,但是每个程序员也应该考虑到提供鼠标支持。鼠标用户所期望的一件事就是能够在应用程序中实现拖放。如果你注意到一些大型应用程序或windows自身的话,拖放操作几乎随处可见。例如,用户可能已经习惯了在windows资源管理器中拖放文件,或在word中拖放文本等操作了。尽管拖放操作随处可见,但是只有极少数程序员在他们所编写的程序中实现拖放功能,最可能的原因是他们认为实现拖放可能比想象的还要难。这篇文章列举了如何在窗体内、窗体之间,甚至应用程序之间移动文本、图片或者文件的例子,显示了在vb.net中实现拖放是非常容易得。拖放如何进行拖放实际上就如同用鼠标复制粘帖,因此你必须有一个可以复制或移动的源,也要有一个可以粘贴的目的地。在这两个操作过程中,数据是保存在内存中的。复制粘贴用的是剪切版,而拖放用的却是一种本质上是私有剪切板的dataobject的对象。下面是典型的托放操作的时间序列: 1、拖(dragging)是通过调用源控件的dodragdrop方法来初始化的,dodragdrop有两个参数 data,指定将要传送的数据 allowedeffects,指定允许进行的操作(复制或移动)这样自动创建了一个新的dataobject对象 2、接下来就依次激发了givefeedback事件。在大多数情况下,你并不需要担心givefeedback事件,然而你如果想自定义拖放过程中的鼠标指针的话,你可以在这些地方加上你的代码。 3、任何有allowdrop属性而且被设置成true的控件都是隐含的drop对象。allowdrop属性可以在设计时的属性窗口中进行设置,也可以在form_load事件自动加载。 4、当鼠标移到某个控件时,就同时激发了这个控件的dragenter事件。getdatapresent方法是用来确认拖过来的数据是否适合目标控件,effect属性是用来显示适当的鼠标指针。 5、如果用户在有效的目标控件上释放鼠标,就同时激发了dragdrop事件。dragdrop事件句柄中的代码从dataobject对象中释放数据并把它显示在目标控件中。从vb6到vb.net有何变化?(略)拖放文本拖放操作的一个很简单然而很有用的情形是从一个textbox控件复制文本到另一个textbox控件。当然你可以只用键盘就能实现(ctrl + c and ctrl + v),然而拖放更简单因为它仅需要鼠标的移动就可以完成。 1、向一个窗体中添加两个文本框,并把第二个textbox控件的allowdrop属性设置成true,添加如下代码。 private mouseisdown as boolean = false private sub textbox1_mousedown(byval sender as object, byval e as _ system.windows.forms.mouseeventargs) handles textbox1.mousedown ' set a flag to show that the mouse is down. mouseisdown = true end sub private sub textbox1_mousemove(byval sender as object, byval e as _ system.windows.forms.mouseeventargs) handles textbox1.mousemove if mouseisdown then ' initiate dragging. textbox1.dodragdrop(textbox1.text, dragdropeffects.copy) end if mouseisdown = false end sub private sub textbox2_dragenter(byval sender as object, byval e as _ system.windows.forms.drageventargs) handles textbox2.dragenter ' check the format of the data being dropped. if (e.data.getdatapresent(dataformats.text)) then ' display the copy cursor. e.effect = dragdropeffects.copy else ' display the no-drop cursor. e.effect = dragdropeffects.none end if end sub private sub textbox2_dragdrop(byval sender as object, byval e as _ system.windows.forms.drageventargs) handles textbox2.dragdrop ' paste the text. textbox2.text = e.data.getdata(dataformats. end sub 在上面的例子中,mousedown事件是用来判断鼠标是否按下的,mousemove事件中用到了dodragdrop方法。尽管你可以在mousedown事件中来初始化drag,然而这么做会带来出人意料之外的结果。在用户点击控件时,将显示no-drag 指针。dodragdrop方法有两个参数 data,这个例子中代表的是第一个textbox的text属性。 allowedeffects,这个例子中是只允许复制。在mousemove事件中mouseisdown标志设置成了false,尽管在这个例子没有必要,但是如果你有很多控件支持拖放时,你将会得到一个运行时例外。在dragenter事件中,getdatapresent方法检查正在拖动的数据格式,在本例中是文本,所以effect属性设置成复制,同时也显示copy指针。在dragdrop事件中,getdata方法用来从dataobject中获得文本,并把它送给目标文本框。拖动图片尽管拖放图片并不像拖放文本那样经常用到,然而它在许多应用程序中仍然是很有用的。实际上这两者之间也没有什么不同,只不过是数据类型发生了变化而已。 1、 在form中添加两个picturebox控件。 2、 在代码窗体中添加如下代码 private sub form1_load(byval sender as system.object, byval e as _ system.eventargs) handles mybase.load ' enable dropping. picturebox2.allowdrop = true end sub private sub picturebox1_mousedown(byval sender as object, byval e as _ system.windows.forms.mouseeventargs) handles picturebox1.mousedown if not picturebox1.image is nothing then ' set a flag to show that the mouse is down. m_mouseisdown = true end if end sub private sub picturebox1_mousemove(byval sender as object, byval e as _ system.windows.forms.mouseeventargs) handles picturebox1.mousemove if m_mouseisdown then ' initiate dragging and allow either copy or move. picturebox1.dodragdrop(picturebox1.image, dragdropeffects.copy or _ dragdropeffects.move) end if m_mouseisdown = false end sub private sub picturebox2_dragenter(byval sender as object, byval e as _ system.windows.forms.drageventargs) handles picturebox2.dragenter if e.data.getdatapresent(dataformats.bitmap) then ' check for the ctrl key. if e.keystate = 9 then e.effect = dragdropeffects.copy else e.effect = dragdropeffects.move end if else e.effect = dragdropeffects.none end if end sub private sub picturebox2_dragdrop(byval sender as object, byval e as _ system.windows.forms.drageventargs) handles picturebox2.dragdrop ' assign the image to the picturebox. picturebox2.image = e.data.getdata(dataformats.bitmap) ' if the ctrl key is not pressed, delete the source picture. if not e.keystate = 8 then picturebox1.image = nothing end if end sub 注意到上面的例子中第二个picturebox控件的allowdrop属性是在form1_load事件中设置的,这是因为设计时picturebox并没有allowdrop属性。在mousedown事件中,代码首先检测是否有要赋给picturebox的图片;如果没有的话,当你移动图片后,接下来的click将引发一个意外。还应该注意到的是在dragenter和dragdrop事件中代码检测ctrl键是否被按下,从而决定是否是复制还是移动图片。为什么值会不同呢?在dragenter事件中,当鼠标左键按下时,产生的值是1,在加上ctrl的值8,从而值为9。见keystate枚举列表drageventargs.keystate property(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformsdrageventargsclasskeystatetopic.asp)。到目前为止,这两个例子处理的都是同一窗体不同控件间的拖放,然而在同一应用程序的不同窗体上同样适用。拖动文件在windows中拖放通常是复制或移动文件,windows完全支持该功能,而且对许多用户来说这也是操作文件的优选方式。除此之外,用户已经习惯了把文件拖动到一个程序来打开文件的方式,像拖动一个doc文件到word来打开。在这个例子中用从windows资源管理器拖来的文件来操作listbox控件。向窗体中添加一个listbox控件,并设置其allowdrop属性为true,并添加如下代码: private sub listbox1_dragenter(byval sender as object, byval e as _ system.windows.forms.drageventargs) handles listbox1.dragenter if e.data.getdatapresent(dataformats.filedrop) then e.effect = dragdropeffects.all end if end sub private sub listbox1_dragdrop(byval sender as object, byval e as _ system.windows.forms.drageventargs) handles listbox1.dragdrop if e.data.getdatapresent(dataformats.filedrop) then dim myfiles() as string dim i as integer ' assign the files to an array. myfiles = e.data.getdata(dataformats.filedrop) ' loop through the array and add the files to the list. for i = 0 to myfiles.length - 1 listbox1.items.add(myfiles(i)) next end if end sub 你可能已经注意到了dragenter事件中的effect属性被设置成dragdropeffects.all。因为文件本身并不是真的就被复制或移动了,因此源控件设置成哪个allowedeffects并没有关系,所以指定all对任何filedrop都可以。在上面的例子中filedrop格式包含了每个被拖动文件的全路径。下面的例子讲述了拖放的一个特殊情况:在两个列表间来回拖放。表间拖放拖放的另一个情况是从一个列表移动项目到另一个列表。这种情况下拖放将变得更加简单。向窗体中添加两个listview控件,并把他们的allowdrop、multiselect、view属性分别设置成true、true、list。并添加如下代码: private sub listview_itemdrag(byval sender as object, byval e as _ system.windows.forms.itemdrageventargs) handles listview1.itemdrag, _ listview2.itemdrag dim myitem as listviewitem dim myitems(sender.selecteditems.count - 1) as listviewitem dim i as integer = 0 ' loop though the selecteditems collection for the source. for each myitem in sender.selecteditems ' add the listviewitem to the array of listviewitems. myitems(i) = myitem i = i + 1 next ' create a dataobject containg the array of listviewitems. sender.dodragdrop(new _ dataobject("system.windows.forms.listviewitem()", myitems), _ dragdropeffects.move) end sub private sub listview_dragenter(byval sender as object, byval e as _ system.windows.forms.drageventargs) handles listview1.dragenter, _ listview2.dragenter ' check for the custom dataformat listviewitem array. if e.data.getdatapresent("system.windows.forms.listviewitem()") then e.effect = dragdropeffects.move else e.effect = dragdropeffects.none end if end sub private sub listview_dragdrop(byval sender as object, byval e as _ system.windows.forms.drageventargs) handles listview1.dragdrop, _ listview2.dragdrop dim myitem as listviewitem dim myitems() as listviewitem = _ e.data.getdata("system.windows.forms.listviewitem()") dim i as integer = 0 for each myitem in myitems ' add the item to the target list. sender.items.add(myitems(i).text) ' remove the item from the source list. if sender is listview1 then listview2.items.remove(listview2.selecteditems.item(0)) else listview1.items.remove(listview1.selecteditems.item(0)) end if i = i + 1 next end sub 你可能不明白为什么这个例子中用的是listview控件而不是listbox控件,这个问题题的好,因为listbox控件不支持多项拖放。 listview和treeview控件有个itemdrag事件。上面的例子中,一个itemdrag事件句柄覆盖了两个控件,并在列在handles从句。sender参数表明哪个控件正在初始化drag。因为dataformats类没有listviewitem类型成员,数据必须传递给一个系统类型。itemdrag创建了一个listviewitem类型的数组,并用一个循环来遍历selecteditem集合。在dodragdrop方法中,创建了一个新的dataobject并用数组来来对它进行操作。可以用这种方法来拖放任何系统类型。结论:正像你从这些例子中所看到的一样,为应用程序添加拖放操作并不是很难。当你理解了这些基本的技巧后,你就可以为你自己的程序添加拖放的代码了