C#中实现拖放操作-程序员宅基地

技术标签: c#  components  string  null  listview  object  

随着桌面系统的推出,利用鼠标的拖放(Drag and Drop)操作由于其简单、直接,受到了越来越多的读者的欢迎,为迎合这种趋势,越来越多程序员在自己的程序中使用了拖放操作。拖放操作方便了程序的使用者,但由于拖放操作在程序中的设计工作比较还有点麻烦,甚至是一个难点,许多程序员对其都有点心有余悸。本文就结合微软公司最新的.Net程序开发语言--C#,来全面介绍一下在C#中是如何处理拖放操作的。

    在本文中,我们是通过二个代表组件,也是在拖放操作中经常使用到的二个组件--TreeView组件和ListView组件,之间互相进行拖放操作来说明此类问题的。在进行拖放操作之前,必须要对进行拖放操作的组件的"AllowDrop"属性值设定为"True",因为此属性是确定组件是否可以进行拖放操作的。

    一.本文中介绍的程序的设计和运行的软件环境:

    (1).微软公司视窗2000服务器

    (2)..Net FrameWork SDK Beta 2

    二.由TreeView组件到ListView组件的拖放操作:

    要完成此次的拖放操作,必须处理好三种事件:"ItemDrag"、"DragEnter"、"DragDrop"。其中只有第一种事件是在源组件中触发的,另外二种事件是在目标组件中触发的。其中当用户拖动组件触发"ItemDrag"事件;当拖动数据进入目标组件区域触发"DragEnter"事件;当用户在目标组件区域放置拖动的数据触发"DragDrop"事件。下面就根据拖放操作的操作顺序来详细介绍:

    (1).开始"拖"(Drag)操作:

    通过"DoDragDrop"方法拉开了拖放操作的第一步。"DoDragDrop"方法的语法为:

    DoDragDrop ( object data , DragDropEffects allowedEffects ) ;

    其中第二个参数来是说明此次拖放操作最后所要实现的效果,因为拖放操作有时实现的效果是把源组件中的内容"拖"到目标组件中,这种效果就是"Move";有时拖放的效果是在目标组件中加入拖动的数据,对源组件的内容是没有什么影响的,这种效果就是"Copy"。当然无论是"Move"还是"Copy",这都要通过具体的编程来实现,设定这些效果只是告诉操作系统,你进行拖放操作的类型,从而为拖放操作设定特定的图标。此例中实现开始"拖放"操作的具体实现代码如下:

    private void treeView1_ItemDrag ( object sender , ItemDragEventArgs e )

    {

    string strItem = e.Item.ToString ( ) ;

    //开始进行"Drag"操作

    DoDragDrop ( strItem , DragDropEffects.Copy | DragDropEffects.Move ) ;

    }

    在上面代码中,我们定义的拖放数据类型是字符串,其实拖放的数据类型可以是很多种的,你可以通过修改"DoDragDrop"方法的第一个参数来设定你所要拖放数据类型,譬如:位图或者其他什么。

    (2).目标组件允许进行拖放操作:

    既然你已经开始进行拖放操作,你还必须告诉你要拖放到的目标组件,要接受你所拖放的数据,"DragEnter"事件正好可以处理。在下列的代码中,我们是通过判断拖放数据类型来确定是否接受拖放,如果是字符串,则可以,否则,则不行。具体代码如下:

    private void listView1_DragEnter ( object sender , DragEventArgs e )

    {

    //判断是否目前拖动的数据是字符串,如果是,则拖动符串对目的组件进行拷贝if ( e.Data.GetDataPresent ( DataFormats.Text ) ) e.Effect = DragDropEffects.Move ;

    else

    e.Effect = DragDropEffects.None ;

    }

    (3).获得拖放的字符串,在目标组件中加入相应的内容:

    此步的处理过程是十分明确的,要分成二步来进行,首先要得到拖放的字符串,其次是在目标组件中加入以此字符串为标题的项目。当然还要在相应的位置了。下面就是实现这二步操作的具体代码:

    private void listView1_DragDrop ( object sender , DragEventArgs e )

    {

    string dummy = "temp" ;

    //获得进行"Drag"操作中拖动的字符串

    string s = ( string ) e.Data.GetData ( dummy.GetType ( ) ) ;

    s = s.Substring ( s.IndexOf ( ":" ) + 1 ).Trim ( ) ;

    Position.X = e.X ;

    Position.Y = e.Y ;

    Position = listView1.PointToClient ( Position ) ;

    //在目标组件中加入以此字符串为标题的项目

    listView1.Items.Add ( new ListViewItem ( s , 0 ) ) ;

    }

    此致通过对这三个事件的编程,已经完成了由TreeView组件到ListView组件的拖放操作。

三.由ListView组件到TreeView组件的拖放操作:

    由ListView组件到TreeView组件的拖放操作和从TreeView组件到ListView组件相类似,也是通过"ItemDrag"、"DragEnter"、"DragDrop"三个事件来处理的,具体如下:

    (1).开始"拖"(Drag)操作:

    这和前者没有什么实质上的区别,只是在此次的拖放操作开始之前,多加入了一些逻辑判断,让程序更稳健的允许,实现的代码如下:

    private void listView1_ItemDrag ( object sender , ItemDragEventArgs e )

    {

    //判断是否是鼠标右键按动

    if ( e.Button == MouseButtons.Right ) return ;

    int nTotalSelected = listView1.SelectedIndices.Count ;

    //判断组件中是否存在项目

    if ( nTotalSelected <= 0 ) return ;

    IEnumerator selCol = listView1.SelectedItems.GetEnumerator ( ) ;

    selCol.MoveNext ( ) ;

    ListViewItem lvi = ( ListViewItem )selCol.Current ;

    string mDir = "" ;

    for ( int i = 0 ; i < lvi.SubItems.Count ; i++ ) mDir += lvi.SubItems[ i ].Text + " ," ;

    string str = mDir.Substring ( 0 , mDir.Length-1 ) ;

    if ( str == "" ) return ;

    //对组件中的字符串开始拖放操作

    listView1.DoDragDrop ( str , DragDropEffects.Copy | DragDropEffects.Move ) ;

    }

    (2).目标组件允许进行拖放操作:

    这一步是进行拖放操作最为一致的,除非你所要进行拖放的数据类型有改变,否则,没有必要对源代码进行什么修改,具体如下:

    private void treeView1_DragEnter ( object sender , DragEventArgs e )

    {

    //判断是否目前拖动的数据是字符串,如果是,则拖动符串对目的组件进行拷贝if ( e.Data.GetDataPresent ( DataFormats.Text ) ) e.Effect = DragDropEffects.Copy ;

    else

    e.Effect = DragDropEffects.None ;

    }

    (3).获得拖放的字符串,在目标组件中加入相应的内容:

    对于进行拖放操作的不同组件,获得其拖放的数据的实现方法是不一样的,在本步骤中也不例外,但总归大同小异,掌握程序设计的步骤和要点,加上探索、研究的精神,这个问题应该能够解决,下面是实现此步骤的程序代码:

    private void treeView1_DragDrop ( object sender , DragEventArgs e )

    {

    //获得进行"Drag"操作中拖动的字符串

    string dummy = "temp" ;

    string s = ( string ) e.Data.GetData ( dummy.GetType ( ) ) ;

    s = s.Substring ( s.IndexOf ( ":" ) + 1 ).Trim ( ) ;

    Position.X = e.X ;

    Position.Y = e.Y ;

    Position = treeView1.PointToClient ( Position ) ;

    TreeNode DropNode = this.treeView1.GetNodeAt ( Position ) ;

    //在目标组件中加入以此字符串为标题的项目

    if ( DropNode != null )

    {

    TreeNode DragNode = new TreeNode ( s ) ;

    treeView1.Nodes.Insert ( DropNode.Index+1 , DragNode ) ;

    }

    }

四. 二个组件进行拖放操作的完整源程序代码(dragdrop.cs):

    在掌握了上面的这些步骤过以后,可以得到这二个组件相互进行拖放操作的完整代码和编译后程序的运行界面,如下:

    图01:二个组件相互进行拖放的程序运行界面

    dragdrop.cs的代码如下:

    using System ;

    using System.Drawing ;

    using System.Collections ;

    using System.ComponentModel ;

    using System.Windows.Forms ;

    using System.Data ;

    //导入程序中使用的命名空间

    public class Form1 : Form

    {

    private TreeView treeView1 ;

    private Point Position = new Point( 0 , 0) ;

    // bool lv1_mdown = false ;

    private ListView listView1 ;

    private System.ComponentModel.Container components = null ;

    public Form1 ( )

    {

    InitializeComponent ( ) ;

    //初始化窗体中的各个组件

    }

    //清除程序中使用到的各种资源

    protected override void Dispose ( bool disposing )

    {

    if ( disposing )

    {

    if ( components != null )

    {

    components.Dispose ( ) ;

    }

    }

    base.Dispose ( disposing ) ;

    }

    private void InitializeComponent ( )

    {

    ListViewItem listViewItem1 = new ListViewItem ( "Item01" ) ;

    ListViewItem listViewItem2 = new ListViewItem ( "Item02" ) ;

    treeView1 = new TreeView ( ) ;

    listView1 = new ListView ( ) ;

    SuspendLayout ( ) ;

    //此属性必须设定为"真",这样才能进行拖放操作treeView1.AllowDrop = true ;

    treeView1.ImageIndex = -1 ;

    treeView1.Location = new Point ( 48 , 40 ) ;

    treeView1.Name = "treeView1" ;

    //在TreeView组件中加入初始化的节点

    treeView1.Nodes.Add ( new TreeNode ( "节点01" ) );

    treeView1.Nodes.Add ( new TreeNode ( "节点02" ) );

    treeView1.SelectedImageIndex = -1 ;

    treeView1.Size = new Size ( 121 , 144 ) ;

    treeView1.TabIndex = 0 ;

    treeView1.DragEnter += new DragEventHandler ( treeView1_DragEnter ) ;

    treeView1.ItemDrag += new ItemDragEventHandler ( treeView1_ItemDrag ) ;

    treeView1.DragDrop += new DragEventHandler ( treeView1_DragDrop ) ;

    //此属性必须设定为"真",这样才能进行拖放操作listView1.AllowDrop = true ;

    //在ListView组件中加入项目

    listView1.Items.Add ( listViewItem1 ) ;

    listView1.Items.Add ( listViewItem2 ) ;

    listView1.Location = new Point ( 208 , 40 ) ;

    listView1.Name = "listView1" ;

    listView1.Size = new Size ( 121 , 144 ) ;

    listView1.TabIndex = 2 ;

    listView1.View = View.List ;

    listView1.DragDrop += new DragEventHandler ( listView1_DragDrop ) ;

    listView1.DragEnter += new DragEventHandler ( listView1_DragEnter ) ;

    listView1.ItemDrag += new ItemDragEventHandler ( listView1_ItemDrag ) ;

    AutoScaleBaseSize = new Size ( 6 , 14 ) ;

    ClientSize = new Size ( 376 , 237 ) ;

    Controls.Add ( listView1 );

    Controls.Add ( treeView1 );

    this.MaximizeBox = false ;

    this.MinimizeBox = false ;

    this.Name = "Form1" ;

    this.Text = "全面掌握C#中的拖放操作" ;

    this.ResumeLayout ( false ) ;

    }

static void Main ( )

    {

    Application.Run ( new Form1 ( ) ) ;

    }

    private void treeView1_ItemDrag ( object sender , ItemDragEventArgs e )

    {

    string strItem = e.Item.ToString ( ) ;

    //开始进行"Drag"操作

    DoDragDrop ( strItem , DragDropEffects.Copy | DragDropEffects.Move ) ;

    }

    private void listView1_DragEnter ( object sender , DragEventArgs e )

    {

    //判断是否目前拖动的数据是字符串,如果是,则拖动符串对目的组件进行拷贝if ( e.Data.GetDataPresent ( DataFormats.Text ) ) e.Effect = DragDropEffects.Move ;

    else

    e.Effect = DragDropEffects.None ;

    }

    private void listView1_DragDrop ( object sender , DragEventArgs e )

    {

    string dummy = "temp" ;

    //获得进行"Drag"操作中拖动的字符串

    string s = ( string ) e.Data.GetData ( dummy.GetType ( ) ) ;

    s = s.Substring ( s.IndexOf ( ":" ) + 1 ).Trim ( ) ;

    Position.X = e.X ;

    Position.Y = e.Y ;

    Position = listView1.PointToClient ( Position ) ;

    //在目标组件中加入以此字符串为标题的项目

    listView1.Items.Add ( new ListViewItem ( s , 0 ) ) ;

    }

    private void listView1_ItemDrag ( object sender , ItemDragEventArgs e )

    {

    //判断是否是鼠标右键按动

    if ( e.Button == MouseButtons.Right ) return ;

    int nTotalSelected = listView1.SelectedIndices.Count ;

    //判断组件中是否存在项目

    if ( nTotalSelected <= 0 ) return ;

    IEnumerator selCol = listView1.SelectedItems.GetEnumerator ( ) ;

    selCol.MoveNext ( ) ;

    ListViewItem lvi = ( ListViewItem )selCol.Current ;

    string mDir = "" ;

    for ( int i = 0 ; i < lvi.SubItems.Count ; i++ ) mDir += lvi.SubItems[ i ].Text + " ," ;

    string str = mDir.Substring ( 0 , mDir.Length-1 ) ;

    if ( str == "" ) return ;

    //对组件中的字符串开始拖放操作

    listView1.DoDragDrop ( str , DragDropEffects.Copy | DragDropEffects.Move ) ;

    }

private void treeView1_DragEnter ( object sender , DragEventArgs e )

    {

    //判断是否目前拖动的数据是字符串,如果是,则拖动符串对目的组件进行拷贝if ( e.Data.GetDataPresent ( DataFormats.Text ) ) e.Effect = DragDropEffects.Copy ;

    else

    e.Effect = DragDropEffects.None ;

    }

    private void treeView1_DragDrop ( object sender , DragEventArgs e )

    {

    //获得进行"Drag"操作中拖动的字符串

    string dummy = "temp" ;

    string s = ( string ) e.Data.GetData ( dummy.GetType ( ) ) ;

    s = s.Substring ( s.IndexOf ( ":" ) + 1 ).Trim ( ) ;

    Position.X = e.X ;

    Position.Y = e.Y ;

    Position = treeView1.PointToClient ( Position ) ;

    TreeNode DropNode = this.treeView1.GetNodeAt ( Position ) ;

    //在目标组件中加入以此字符串为标题的项目

    if ( DropNode != null )

    {

    TreeNode DragNode = new TreeNode ( s ) ;

    treeView1.Nodes.Insert ( DropNode.Index+1 , DragNode ) ;

    }

    }

    }

    五.其他组件的拖放操作:

    本文虽然对TreeView组件和ListView组件之间的拖放操作进行了详细的介绍,对于其他的可以用于拖放操作的组件,很多组件的拖放操作的实现方法都和这二种差不多。但也有一些组件有一些区别,譬如:ListBox组件等,在进行拖放操作的时候,他就没有本文介绍的"ItemDrag"事件,那这怎么办。我们是通过一个变通的方法来实现的。具体是通过"MouseMove"事件和"MouseDown"事件来代替"ItemDrag"事件,其中"MouseMove"事件主要是起到触发拖放操作的作用,"MouseDown"事件主要是起着判断此次拖放操作是否已经完成的作用。对于ListBox组件拖放操作的其他步骤也和上面介绍的二个组件没有什么太大区别。由于篇幅的关系ListBox组件和其他不存在"ItemDrag"事件的组件的拖放操作,这里就不一一介绍了,相信大家能够搞定。

    六.总结:

    对于大多数组件来说掌握了"ItemDrag"、"DragEnter"、"DragDrop"三个事件的解决办法也就掌握了组件间的拖放操作。当然还有一些例外的组件,但总而言之,拖放操作的实现步骤都是一样的,解决的思路也是大致一致的。由于拖放操作的自身的优点,对于程序员来说尽快掌握是十分必要的,希望本文介绍的内容能够令你满意。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/feng991254/article/details/5453803

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签