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