
圖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.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

