注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

分享,态度 ·~~

—— 十年太长,五年;如果可以回到五年前,你最想对那时候的自己说什么?

 
 
 

日志

 
 

C# 拖放操作源码详解(二)  

2010-02-02 18:52:22|  分类: DotNet |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

在Windows资源管理器中使用拖放操作来移动或复制文件是大家所惯用的方式。Windows资源管理器充分支持拖放操作,而且这也是非常多用户所偏爱的文件使用方式。此外,许多用户非常习惯直接从Windows资源管理器将文件拖放至对应的应用程序中来打开它们。例如,从Windows资源管理器将一个.doc 文档拖放至Microsoft Word即会将该文档在Microsoft Word中打开。

C 拖放操作源码详解(二) - 乂乂 - 一个人,一支烟  ·~~

图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]);
}
}
}

C 拖放操作源码详解(二) - 乂乂 - 一个人,一支烟  ·~~

图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控件:
private void CH4_DemoForm067_Load(object sender, EventArgs e)
{
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;
}
}

C 拖放操作源码详解(二) - 乂乂 - 一个人,一支烟  ·~~

图8.17使用拖放操作来移动节点

C 拖放操作源码详解(二) - 乂乂 - 一个人,一支烟  ·~~

图8.18使用拖放操作来复制节点

【from http://hi.baidu.com/feiyangqingyun/blog/item/315625f99e58d451252df2b1.html

  评论这张
 
阅读(1748)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017