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

智能推荐

apache ETag头信息泄露的漏洞整改_apache web server etag header信息泄露漏洞-程序员宅基地

文章浏览阅读4.2k次。apache ETag头信息泄露的漏洞绕了很多弯路,最后通过以下方式解决1.在apache2的httpd.conf配置 Header unset ETag FileETag none2.重启apache,发现启动会报错-“找不到header”。可能是没有header的mod,去apache的mods-available文件找“headers.load”,手动去mods-en..._apache web server etag header信息泄露漏洞

java面试基础篇-程序员宅基地

文章浏览阅读131次。反射机制是在运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意个对象,都能 够调用它的任意一个方法。在java中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

spring源码 - 条件注解@ConditionnalOnClass的原理分析_conditionalonclass-程序员宅基地

文章浏览阅读3.9k次,点赞5次,收藏9次。用过springboot的小伙伴们都知道,相比于spring,它最大的优势是帮我们省去了一大堆超大一堆繁琐的配置。比如在spring中,当我们需要在项目中整合第三方插件(如redis、mybatis、rabbitmq)时,往往需要在xml配置文件中去配置这些插件的等将其与spring进行整合。而在springboot中,他会根据项目中引入哪些插件自动地将插件进行整合,这都得益于springboot的自动装配或称为自动配置。_conditionalonclass

【附源码】基于flask框架基于高校大学生校园社交系统 (python+mysql+论文)-程序员宅基地

文章浏览阅读838次,点赞21次,收藏9次。因此,开发一款基于高校大学生校园社交系统,旨在为大学生提供一个更加贴心、便捷的社交平台,满足他们在校园生活中的各种社交需求。综上所述,基于高校大学生校园社交系统的开发不仅可以满足大学生在校园生活中的社交需求,还可以为他们提供一个展示自我、锻炼能力的舞台,同时也有助于提高校园信息的透明度和便利性。在数据库管理工具的选择上,使用了Navicat 11,这是一个用户友好且功能强大的数据库管理软件,它支持多种数据库系统,包括MySQL,并提供了图形化界面,使得数据库的管理和维护工作更加便捷。系统的选题背景和意义。

Windows 7 驱动开发-程序员宅基地

文章浏览阅读112次。 本文是对Win7(64)+VS2010+WDK7.1.0(WinDDK\7600.16385.1)开发驱动的小结。 一、系统工具 1、Win7(amd64位)系统注:已装系统后,管理员身份运行cmd命令,查看bcdedit /set testsigning true、bcdedit /debug on 等命令是否运行成功。若失败,请将bcdedit命令所在文件夹boo..._win7 开发驱动

关于reids-程序员宅基地

文章浏览阅读62次。redis 官网(英文):https://redis.io/ redis 手册(中文): http://doc.redisfans.com/ redis 中文网(中文) : http://www.redis.net.cn/ redis 教程(中文) : http://www.redis.net.cn/tutorial/3501.html开始做,坚持做,...

随便推点

Visual Studio 添加外部.cpp/.h文件_visual studio 新页面生成.cpp .h文件-程序员宅基地

文章浏览阅读8.8k次,点赞8次,收藏34次。1.右键“源文件”,点击“添加”-->“现有项”2.选择需要添加的文件,点击添加3.右键项目名称,点击“属性”4.选择“C/C++”下的“常规”5.点击“附加包含目录下”下的编辑,完成文件路径添加..._visual studio 新页面生成.cpp .h文件

【配置环境】在虚拟机的Ubuntu下安装VS Code并配置C/C++运行环境_vmware下ubuntu系统中安装vscode-程序员宅基地

文章浏览阅读3.7k次,点赞2次,收藏26次。Ubuntu下VSCode安装和配置C/C++运行环境,保姆级详细!!!_vmware下ubuntu系统中安装vscode

Web背景铺满屏幕 属性:background-image_怎么webstrom背景铺满网页-程序员宅基地

文章浏览阅读605次。记录:学习web中背景铺满且固定位置。_怎么webstrom背景铺满网页

【模型制作】如何把模之屋的模型导入UE_模之屋的模型怎么导入blender-程序员宅基地

文章浏览阅读1.3k次,点赞11次,收藏8次。blender去官网下载,我下载的是此时最新版本3.6版本,如果上不了github,可以从这里下载插件:链接:https://pan.baidu.com/s/1FnEb5W_y8Wap3IVyydCqvQ?编辑-偏好设置-插件-安装,直接点击压缩包安装即可。(此步可以略过)点击骨骼,左上角点击姿态模式,(鼠标中键转动视角,shirf+鼠标中键移动视角),点击骨骼,按对应的快捷键检查骨骼。6,点击这个,取消勾选fix mmd(如果是mmd文件则不需要取消勾选),然后点击Fix Model。_模之屋的模型怎么导入blender

Windows安装RedisJSON 模块_windows安装json-程序员宅基地

文章浏览阅读936次。RedisJSON 是使用 C 语言编写的,因此需要通过 Visual Studio Build Tools 来编译源代码。其中,/path/to/redisjson.dll 是 redisjson.dll 的绝对路径。这会在 RedisJSON 源代码根目录下的 build 目录中生成一个 redisjson.dll 文件,这个文件就是 RedisJSON 模块的库文件。你可以从 RedisJSON 的官方库中下载其源代码,在 Windows 上建议使用 Git Bash 或者是使用 Git 命令下载。_windows安装json

Lua之table新增整数键值-程序员宅基地

文章浏览阅读1.6k次。作者:糊涂小蜗牛链接:https://www.jianshu.com/p/42d7d0b82708来源:简书lua表分为数组和散列表部分,数组部分从 1 开始作为第一个索引,散列表部分要求键值不能为 nil。因为表包括散列表和数组两部分数据,所以一个以正整数作为键值的数据写入lua表时不确定是写入了数组还是散列表中。接下来讨论这部分的操作原理。虽然正整数作为键值的数据写入lua表时不确定...

推荐文章

热门文章

相关标签