图8.16在两个列表间来回拖放项目
图8.16所示是程序范例CH8_DemoForm014.vb的运行界面。显然,您可以在两个列表间来回拖放一个或多个文件来移动项目。本程序范例的设计重点说明如下:- 由于两个列表的ListView控件都可以作为置放目标,因此务必将这两个ListView控件的AllowDrop属性设定成True。
- 请将两个ListView控件的MultiSelect属性设定成True。
- 请将两个ListView控件的FullRowSelect属性设定成True。
- 以下是程序范例CH8_DemoForm014.vb的程序代码内容。在Load事件处理函数中所调用的 PopulateListView()程序主要是用来初始化两个ListView控件:
ByVal e As System.EventArgs)Handles MyBase.Load
Me.PopulateListView()
End Sub
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(CType(sender, ListView).SelectedItems.Count-1)_
As ListViewItem
Dim i As Integer=0
' 循环处理拖放源的SelectedItems集合。
For Each myItem In CType(sender, ListView).SelectedItems
' 将ListViewItem添加到ListViewItems的数组中。
myItems(i)=myItem
i=i+1
Next
' 创建一个DataObject对象来含有ListViewItem的数组。
CType(sender, ListView).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
' 检查自定义的DataFormat ListViewItem数组。
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=_
CType(_
e.Data.GetData(_
"System.Windows.Forms.ListViewItem()"), _
ListViewItem())
Dim i As Integer=0
For Each myItem In myItems
' 将项目添加到目标列表中。
Dim item As New ListViewItem(myItems(i).Text)
item.SubItems.Add(myItems(i).SubItems(1).Text)
CType(sender, ListView).Items.Add(item)
' 从源列表删除项目。
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
您或许会觉得奇怪,为什么不使用ListBox控件而要使用ListView控件。最主要的理由是,ListBox控件并不支持拖曳多个项目,单击列表会使得多重选择失效。
ListView与TreeView控件都拥有一个ItemDrag事件来促进拖曳。在本范例中,我们使用单一个ItemDrag事件处理函数来处理两个ListView控件的ItemDrag事件。其中的sender参数代表初始化拖拽的控件。
由于DataFormats类的成员并不包括ListViewItem类型,所以数据必须被当作一个系统Type来传递。ItemDrag事件处理函数的程序代码会创建一个类型为ListViewItem的数组并循环处理SelectedItems集合以便填入数组。在DoDragDrop方法中,一个新的DataObject对象会被创建并以数组来填入。您可以使用相同的技巧来拖放任何的系统Type。
在DragDrop事件处理函数中,我们会将DataObject对象中的数组复制到一个新的ListViewItem数组中,而且每一个ListViewItem会被添加到目标ListView控件的Items集合中。
在两个TreeView之间来回拖放节点
图8.17如何在TreeView之间来回拖放节点
图8.18如何在TreeView之间来回拖放节点图8.17与8.18所示是程序范例CH8_DemoForm015.vb的运行界面。显然,您可以在两个TreeView控件间来回拖放一个节点(移动或复制)。本程序范例的程序代码如下所列:
' 声明一个常量以便侦测在拖曳期间CTRL键是否被按下。
Const CtrlMask As Byte=8
' 处理两个TreeView控件的ItemDrag事件。
Private Sub TreeView_ItemDrag(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.ItemDragEventArgs)_
Handles tvwRight.ItemDrag, tvwLeft.ItemDrag
If e.Button=Windows.Forms.MouseButtons.Left Then
' 初始化拖放操作。
DoDragDrop(e.Item, _
DragDropEffects.Move Or DragDropEffects.Copy)
End If
End Sub
' 处理两个TreeView控件的DragDrop事件。
Private Sub TreeView_DragDrop(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.DragEventArgs)_
Handles tvwLeft.DragDrop, tvwRight.DragDrop
' 此变量用来持有被用户所拖曳的节点。
Dim OriginationNode As TreeNode=_
CType(_
e.Data.GetData(_
"System.Windows.Forms.TreeNode"), TreeNode)
' 为一个TreeView控件调用GetDataPresent方法与替
' 一个文字或图像的方式一点不同,原因是TreeNode并不是
' DataFormats类的一个成员。也就是说,它不是一个预先
' 定义的类型。诸如此种状况,您必须使用能够接受一个字符串
' 作为类型的重载版本。
If e.Data.GetDataPresent(_
"System.Windows.Forms.TreeNode", False)Then
Dim pt As Point
Dim DestinationNode As TreeNode
' 取得鼠标指针所在位置的工作区坐标(Client Coordinate)。
pt=CType(sender, TreeView).PointToClient(_
New Point(e.X, e.Y))
' 选取鼠标指针所在位置之下的节点。
DestinationNode=_
CType(sender, TreeView).GetNodeAt(pt)
' 此处的If语句用来确保当用户在他们尝试
' 去拖曳之节点的上方不小心放开鼠标按键的话,
' 不会失去节点。如果您没有去检查目标节点是否
' 就是来源节点,将会使得该节点消失掉。
If DestinationNode.TreeView _
IsNot OriginationNode.TreeView Then
DestinationNode.Nodes.Add(_
CType(OriginationNode.Clone, TreeNode))
' 当添加一个新的节点时展开父节点,如此才会
' 清楚地呈现出拖放操作的结果。如果没有这样
' 做的话,将会显示一个+号。
DestinationNode.Expand()
' 如果CTRL键没有被按下,就将原来的节点删除
' 以便实现移动节点的拖放操作。
If(e.KeyState And CtrlMask)<> CtrlMask Then
OriginationNode.Remove()
End If
End If
End If
End Sub
' 处理两个TreeView控件的DragEnter事件。
Private Sub TreeView_DragEnter(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.DragEventArgs)_
Handles tvwRight.DragEnter, tvwLeft.DragEnter
' 检查被拖曳的数据的类型是否适用于目标控件。
' 如果不适用,则拒绝置放。
If(e.Data.GetDataPresent(_
"System.Windows.Forms.TreeNode"))Then
' 如果在拖曳期间按着CTRL键,则执行复制操作;
' 反之,则执行移动操作。
If(e.KeyState And CtrlMask)=CtrlMask Then
e.Effect=DragDropEffects.Copy
Else
e.Effect=DragDropEffects.Move
End If
Else
e.Effect=DragDropEffects.None
End If
End Sub