C# 拖放操作源码详解2
拖放操作當然并非只限于文字,有許多應用程序都會提供拖放圖片的功能,以便提升操作的便利性。事實上不管是拖放哪一種類型的數據,其間的方法都沒有太大的差異。
程序范例CH8_DemoForm012.cs示范如何在兩個PictureBox控件間拖曳圖片,其功能特性如下所示:
- 如圖8.13所示,您可以使用拖放方式將左側PictureBox控件中的圖片移動至右側的PictureBox控件中,反之亦然;即左右兩個PictureBox控件都可以作為拖放來源與置放目標。
- 值得一提的是,如果您持續按Ctrl鍵,則可以使用拖放方式將左側PictureBox控件中的圖片復制到右側的PictureBox控件中(如圖8.14所示),反之亦然;即左右兩個PictureBox控件都可以作為拖放來源與置放目標。
圖8.13通過拖放操作來移動圖片
圖8.14通過拖放操作來復制圖片
程序范例CH8_DemoForm012.cs在拖放操作方面的程序代碼如下所示:// 聲明一個常量以便偵測在拖曳期間 Ctrl 鍵是否被按下。
const byte CtrlMask = 8;private void CH4_DemoForm065_Load(object sender, EventArgs e)
{
// 由于目前無法在設計工具中去設定 PictureBox 控件
// 的 AllowDrop 屬性,所以必須通過程序代碼來加以設定。
picLeft.AllowDrop = true;
picRight.AllowDrop = true;
}
// 處理左右兩個 PictureBox 控件的 MouseDown 事件。
// 當鼠標指針位于控件的范圍內而且鼠標按鍵被按下時便會引發此事件。
private void PictureBox_MouseDown(System.Object sender,
System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
PictureBox pic = (PictureBox)(sender);
//初始化拖放操作。
if (pic.Image != null)
{
pic.DoDragDrop(pic.Image,
DragDropEffects.Move | DragDropEffects.Copy);
}
}
}
// 處理左右兩個 PictureBox 控件的 DragEnter 事件。
// 當某一個對象被拖曳至控件的范圍內時就會引發該控件的 DragEnter 事件。
private void PictureBox_DragEnter(System.Object sender,
System.Windows.Forms.DragEventArgs e)
{
// 檢查被拖曳資料的類型是否適用于目標控件。如果不適用,則拒絕置放。
if (e.Data.GetDataPresent(DataFormats.Bitmap))
{
// 如果在拖曳期間按 Ctrl 鍵,則執行復制操作;反之,則執行移動操作。
if ((e.KeyState & CtrlMask) == CtrlMask)
{
e.Effect = DragDropEffects.Copy;
}
else
{
e.Effect = DragDropEffects.Move;
}
}
else
{
e.Effect = DragDropEffects.None;
}
}
// 處理左右兩個 PictureBox 控件的 DragDrop 事件。其實只要轉換發送者(sender)然后檢查 Name 屬性以便確認哪一個 PictureBox 控件要移除影像,就可以使用同一個事件處理函數來處理兩個 PictureBox控件的 DragDrop 事件。
private void PictureBox_DragDrop(System.Object sender,
System.Windows.Forms.DragEventArgs e)
{
PictureBox pic = (PictureBox)(sender);
pic.Image = (Bitmap)(e.Data.GetData(DataFormats.Bitmap));
// 如果 Ctrl 鍵沒有被按下的話,就使另外一個 PictureBox 控件(也就是在 DragDrop 事件中并不是 sender 的那一個 PictureBox 控件)中的圖像被移除。
if ((e.KeyState & CtrlMask) != CtrlMask)
{
if (pic.Name == "picLeft")
{
picRight.Image = null;
}
else
{
picLeft.Image = null;
}
}
}
前面這兩個關于文字與圖片的拖放操作范例都是在同一個窗體上的兩個控件間進行,其實它們也可在同一個應用程序的不同窗體上的控件間拖放。下一個程序范例將示范如何接受從另一個應用程序拖放而來的項目,在此程序范例中,將接受從Windows資源管理器拖放而來的文件。
拖放文件
在Windows資源管理器中使用拖放操作來移動或復制文件是大家所慣用的方式。Windows資源管理器充分支持拖放操作,而且這也是非常多用戶所偏愛的文件使用方式。此外,許多用戶非常習慣直接從Windows資源管理器將文件拖放至對應的應用程序中來打開它們。例如,從Windows資源管理器將一個.doc 文檔拖放至Microsoft Word即會將該文檔在Microsoft Word中打開。
圖8.15示范如何從Windows資源管理器中拖放文件
圖8.15所示是程序范例CH8_DemoForm013.cs的運行畫面。顯而易見地,您可以從Windows資源管理器將一個或多個文件拖放至窗體上的ListBox控件中,而被拖放的文件的文件名會被添加到ListBox控件中。以下是CH8_DemoForm013.cs的程序代碼內容:
private void ListBox1_DragEnter(object sender, DragEventArgs e){
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.All;
}
}
private void ListBox1_DragDrop(object sender, DragEventArgs e)
{
if(e.Data.GetDataPresent(DataFormats.FileDrop))
{
string[] MyFiles;
int i;
// 將文件賦給一個數組。
MyFiles = (string[])(e.Data.GetData(DataFormats.FileDrop));
// 循環處理數組并將文件添加到列表中。
for(i = 0;i <= MyFiles.Length - 1;i++)
{
ListBox1.Items.Add(MyFiles[i]);
}
}
}
圖8.16在兩個列表間來回拖放一個或多個文件來移動項目
請注意我們在ListBox控件的DragEnter事件處理函數中將Effect屬性設定成DragDropEffects.All。由于文件本身實際上并沒有被移動或復制,因此拖放源如何設定AllowedEffects將無關緊要,設定All表示對任何的FileDrop都會啟用置放。
就本范例而言,DataFormats.FileDrop格式會含有每一個被置放文件的完整路徑。本范例的操作邏輯是將所有被拖放文件的完整路徑添入ListBox控件中,當然,您可以采用其他方法,比方說,您可以將被拖放的文件在一個MDI(多文件界面)文件窗口中打開。
在兩個列表之間來回拖放項目
另外一項常見的拖放需求是,在兩個列表(ListView控件)之間來回拖放項目。事實上,我們經常會通過一組按鈕來將列表中被選取的項目移至另外一個列表中,不過這樣的操作模式需要兩次鼠標按鍵操作(第一次選取項目,第二次單擊按鈕)。顯然,在這樣的操作需求中,拖放操作會較受青睞,因為它只需單一動作即可完成(選取并拖曳)。
圖8.16所示是程序范例CH8_DemoForm014.cs的運行畫面。顯而易見地,您可以在兩個列表間來回拖放一個或多個文件來移動項目。本程序范例的設計重點說明如下:
- 由于兩個列表的ListView控件都可以作為置放目標,因此務必將這兩個ListView控件的AllowDrop屬性設定成True。
- 請將兩個ListView控件的MultiSelect屬性設定成True。
- 請將兩個ListView控件的FullRowSelect屬性設定成True。
- 以下是程序范例CH8_DemoForm014.cs的程序代碼內容。于Load事件處理函數中所調用的 PopulateListView() 程序主要是用來初始化兩個ListView控件:
{
this.PopulateListView();
}
private void ListView_ItemDrag(object sender,
System.Windows.Forms.ItemDragEventArgs e)
{
ListViewItem[] myItems =
new ListViewItem[((ListView)(sender)).SelectedItems.Count];
int i = 0;
// 循環處理拖放來源的 SelectedItems 集合。
foreach(ListViewItem myItem in
((ListView)(sender)).SelectedItems)
{
// 將ListViewItem新增至ListViewItems的數組中。
myItems[i] = myItem;
i = i + 1;
}
// 建立一個DataObject對象來包含ListViewItem的數組。
((ListView)(sender)).DoDragDrop(new
DataObject("System.Windows.Forms.ListViewItem()",
myItems), DragDropEffects.Move);
}
private void ListView_DragEnter(object sender,
System.Windows.Forms.DragEventArgs e)
{
// 檢查自定義的 DataFormat ListViewItem 數組。
if (e.Data.GetDataPresent(
"System.Windows.Forms.ListViewItem()"))
{
e.Effect = DragDropEffects.Move;
}
else
{
e.Effect = DragDropEffects.None;
}
}
private void ListView_DragDrop(object sender,
System.Windows.Forms.DragEventArgs e)
{
ListViewItem[] myItems =
(ListViewItem[])(
e.Data.GetData("System.Windows.Forms.ListViewItem()"));
int i = 0;
foreach (ListViewItem myItem in myItems)
{
// 將項目添加到目標列表中。
ListViewItem item = new ListViewItem(myItems[i].Text);
item.SubItems.Add(myItems[i].SubItems[1].Text);
((ListView)(sender)).Items.Add(item);
// 從源列表移除項目。
if (sender == ListView1)
{
istView2.Items.Remove(ListView2.SelectedItems[0]);
}
else
{
ListView1.Items.Remove(ListView1.SelectedItems[0]);
}
i = i + 1;
}
}
您或許會覺得奇怪,為什么不使用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與圖8.18所示是程序范例CH8_DemoForm015.cs的運行畫面。顯而易見地,您可以在兩個TreeView控件間來回拖放一個節點(移動或復制)。本程序范例的程序代碼如下所示:// 聲明一個常量以便偵測在拖曳期間 Ctrl 鍵是否被按下。
const byte CtrlMask = 8;// 處理兩個 TreeView 控件的 ItemDrag 事件。
private void TreeView_ItemDrag(System.Object sender,
System.Windows.Forms.ItemDragEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
// 初始化拖放操作。
DoDragDrop(e.Item,
DragDropEffects.Move | DragDropEffects.Copy);
}
}
// 處理兩個 TreeView 控件的 DragDrop 事件。
private void TreeView_DragDrop(System.Object sender,
System.Windows.Forms.DragEventArgs e)
{
// 此變量用來持有被用戶所拖曳的節點。
TreeNode OriginationNode =
(TreeNode)(
e.Data.GetData("System.Windows.Forms.TreeNode"));
// 為一個TreeView控件調用GetDataPresent方法與為一個文字或圖像的方式一點不同,原因是TreeNode并不是DataFormats類的一個成員。也就是說,它不是一個預先定義的類型。諸如此種狀況,您必須使用能夠接受一個字符串作為類型的重載版本。
if (e.Data.GetDataPresent(
"System.Windows.Forms.TreeNode", false))
{
Point pt;
TreeNode DestinationNode;
// 取得鼠標指針所在位置的工作區坐標(Client Coordinate)。
pt = ((TreeView)(sender)).PointToClient(
new Point(e.X, e.Y));
// 選取鼠標指針所在位置之下的節點。
DestinationNode = ((TreeView)(sender)).GetNodeAt(pt);
// 此處的 If 語句用來確保當用戶在他們嘗試去拖曳節點的上方不小心放開鼠標按鍵的話,不會失去節點。如果您沒有去檢查目標節點是否就是源節點,將會使得該節點消失。
if (DestinationNode.TreeView != OriginationNode.TreeView)
{
DestinationNode.Nodes.Add(
(TreeNode)(OriginationNode.Clone()));
// 當添加一個新的節點時展開父節點,如此才會清楚地呈現出拖放操作的結果。如果沒有這樣做的話,將會顯示一個 + 號。
DestinationNode.Expand();
// 如果 Ctrl 鍵沒有被按下,就將原來的節點移除
// 以便實現移動節點的拖放操作。
if ((e.KeyState & CtrlMask) != CtrlMask)
{
OriginationNode.Remove();
}
}
}
}
// 處理兩個 TreeView 控件的 DragEnter 事件。
private void TreeView_DragEnter(System.Object sender,
System.Windows.Forms.DragEventArgs e)
{
// 檢查被拖曳的數據的類型是否適用于目標控件。如果不適用,則拒絕置放。
if (e.Data.GetDataPresent(
"System.Windows.Forms.TreeNode"))
{
// 如果在拖曳期間按著 Ctrl 鍵,則執行復制操作;反之,則執行移動操作。
if ((e.KeyState & CtrlMask) == CtrlMask)
{
e.Effect = DragDropEffects.Copy;
}
else
{
e.Effect = DragDropEffects.Move;
}
}
else
{
e.Effect = DragDropEffects.None;
}
}
圖8.17使用拖放操作來移動節點
圖8.18使用拖放操作來復制節點
轉載于:https://www.cnblogs.com/jxsoft/archive/2011/05/25/2056488.html
總結
以上是生活随笔為你收集整理的C# 拖放操作源码详解2的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于Chrome开源提取的界面开发框架
- 下一篇: STL常用技巧.