Visual C# 2005實(shí)現(xiàn)在兩個列表之間來回拖放項(xiàng)目

2010-08-28 10:50:09來源:西部e網(wǎng)作者:

另外一項(xiàng)常見的拖放需求,就是在兩個列表(ListView控件)之間來回拖放項(xiàng)目。事實(shí)上,我們經(jīng)常會通過一組按鈕來將列表中被選取的項(xiàng)目移至另外一個列表中,不過這樣的操作模式需要兩次的鼠標(biāo)按鍵操作(第一次選取項(xiàng)目,第二次單擊按鈕)。顯然在這樣的操作需求中,拖放操作會較受青睞,因?yàn)樗恍鑶我徊僮骷纯赏瓿?選取并拖曳)。

\

圖8.16在兩個列表間來回拖放項(xiàng)目

圖8.16所示是程序范例CH8_DemoForm014.vb的運(yùn)行界面。顯然,您可以在兩個列表間來回拖放一個或多個文件來移動項(xiàng)目。本程序范例的設(shè)計(jì)重點(diǎn)說明如下:
  • 由于兩個列表的ListView控件都可以作為置放目標(biāo),因此務(wù)必將這兩個ListView控件的AllowDrop屬性設(shè)定成True。
  • 請將兩個ListView控件的MultiSelect屬性設(shè)定成True。
  • 請將兩個ListView控件的FullRowSelect屬性設(shè)定成True。
  • 以下是程序范例CH8_DemoForm014.vb的程序代碼內(nèi)容。在Load事件處理函數(shù)中所調(diào)用的 PopulateListView()程序主要是用來初始化兩個ListView控件:
    Private Sub CH4_DemoForm067_Load(ByVal sender As System.Object, _
    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

    ' 循環(huán)處理拖放源的SelectedItems集合。
    For Each myItem In CType(sender, ListView).SelectedItems
    ' 將ListViewItem添加到ListViewItems的數(shù)組中。
    myItems(i)=myItem
    i=i+1
    Next
    ' 創(chuàng)建一個DataObject對象來含有ListViewItem的數(shù)組。
    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數(shù)組。
    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
    ' 將項(xiàng)目添加到目標(biāo)列表中。
    Dim item As New ListViewItem(myItems(i).Text)
    item.SubItems.Add(myItems(i).SubItems(1).Text)
    CType(sender, ListView).Items.Add(item)

    ' 從源列表刪除項(xiàng)目。
    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控件并不支持拖曳多個項(xiàng)目,單擊列表會使得多重選擇失效。
    ListView與TreeView控件都擁有一個ItemDrag事件來促進(jìn)拖曳。在本范例中,我們使用單一個ItemDrag事件處理函數(shù)來處理兩個ListView控件的ItemDrag事件。其中的sender參數(shù)代表初始化拖拽的控件。
    由于DataFormats類的成員并不包括ListViewItem類型,所以數(shù)據(jù)必須被當(dāng)作一個系統(tǒng)Type來傳遞。ItemDrag事件處理函數(shù)的程序代碼會創(chuàng)建一個類型為ListViewItem的數(shù)組并循環(huán)處理SelectedItems集合以便填入數(shù)組。在DoDragDrop方法中,一個新的DataObject對象會被創(chuàng)建并以數(shù)組來填入。您可以使用相同的技巧來拖放任何的系統(tǒng)Type。
    在DragDrop事件處理函數(shù)中,我們會將DataObject對象中的數(shù)組復(fù)制到一個新的ListViewItem數(shù)組中,而且每一個ListViewItem會被添加到目標(biāo)ListView控件的Items集合中。
    在兩個TreeView之間來回拖放節(jié)點(diǎn)

    \

    圖8.17如何在TreeView之間來回拖放節(jié)點(diǎn)

    \

    圖8.18如何在TreeView之間來回拖放節(jié)點(diǎn)  
    圖8.17與8.18所示是程序范例CH8_DemoForm015.vb的運(yùn)行界面。顯然,您可以在兩個TreeView控件間來回拖放一個節(jié)點(diǎn)(移動或復(fù)制)。本程序范例的程序代碼如下所列:
    ' 聲明一個常量以便偵測在拖曳期間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
    ' 此變量用來持有被用戶所拖曳的節(jié)點(diǎn)。
    Dim OriginationNode As TreeNode=_
    CType(_
    e.Data.GetData(_
    "System.Windows.Forms.TreeNode"), TreeNode)

    ' 為一個TreeView控件調(diào)用GetDataPresent方法與替
    ' 一個文字或圖像的方式一點(diǎn)不同,原因是TreeNode并不是
    ' DataFormats類的一個成員。也就是說,它不是一個預(yù)先
    ' 定義的類型。諸如此種狀況,您必須使用能夠接受一個字符串
    ' 作為類型的重載版本。
    If e.Data.GetDataPresent(_
    "System.Windows.Forms.TreeNode", False)Then
    Dim pt As Point
    Dim DestinationNode As TreeNode

    ' 取得鼠標(biāo)指針?biāo)谖恢玫墓ぷ鲄^(qū)坐標(biāo)(Client Coordinate)。
    pt=CType(sender, TreeView).PointToClient(_
    New Point(e.X, e.Y))

    ' 選取鼠標(biāo)指針?biāo)谖恢弥碌墓?jié)點(diǎn)。
    DestinationNode=_
    CType(sender, TreeView).GetNodeAt(pt)

    ' 此處的If語句用來確保當(dāng)用戶在他們嘗試
    ' 去拖曳之節(jié)點(diǎn)的上方不小心放開鼠標(biāo)按鍵的話,
    ' 不會失去節(jié)點(diǎn)。如果您沒有去檢查目標(biāo)節(jié)點(diǎn)是否
    ' 就是來源節(jié)點(diǎn),將會使得該節(jié)點(diǎn)消失掉。
    If DestinationNode.TreeView _
    IsNot OriginationNode.TreeView Then
    DestinationNode.Nodes.Add(_
    CType(OriginationNode.Clone, TreeNode))
    ' 當(dāng)添加一個新的節(jié)點(diǎn)時展開父節(jié)點(diǎn),如此才會
    ' 清楚地呈現(xiàn)出拖放操作的結(jié)果。如果沒有這樣
    ' 做的話,將會顯示一個+號。
    DestinationNode.Expand()
    ' 如果CTRL鍵沒有被按下,就將原來的節(jié)點(diǎn)刪除
    ' 以便實(shí)現(xiàn)移動節(jié)點(diǎn)的拖放操作。
    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
    ' 檢查被拖曳的數(shù)據(jù)的類型是否適用于目標(biāo)控件。
    ' 如果不適用,則拒絕置放。
    If(e.Data.GetDataPresent(_
    "System.Windows.Forms.TreeNode"))Then
    ' 如果在拖曳期間按著CTRL鍵,則執(zhí)行復(fù)制操作;
    ' 反之,則執(zhí)行移動操作。
    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
    關(guān)鍵詞:VS.NET