C#-窗体元素的拖拽实现

​ 拖拽操作其实与剪切与粘贴没有什么不同,只不过是它是使用鼠标而不是键盘,在两类操作中,都会有一个来源(被拖拽、被剪切的文字)和目标(拖往的、被粘贴的位置)。无论哪种操作,都会在内存中存在数据的一份副本,在剪切操作中会使用到剪切板,而在拖拽操作中,会使用到DataObject对象,这个DataObject对象就好比是一个私有的剪切板

在应用程序中,是通过一系列事件,如DragEnter,DragLeave和DragDrop事件来实现在Windows应用程序中的拖拽操作。

注意:只有当控件的AllowDrag属性为true时才能拖拽

AllowDrop属性被设定成True的任何控件都可以是置放目标。您可以在设计阶段在“属性”窗口中将要作为目标控件的AllowDrop属性设定成True,或者是于运行阶段在窗体的Load事件处理函数中将要作为目标控件的AllowDrop属性设定成True。

拖放操作在代码中是通过三步实现的:

  1. 首先是启动拖放操作,在需要拖动数据的控件上实现MouseDown事件的响应代码,并调用DoDragDrop方法实现

    MouseDown:当鼠标指针落在组件上方,并按下鼠标按钮时发生

    关于DoDragDrop方法,在类库中的定义为:

    public DragDropEffects DoDragDrop(object data, DragDropEffects allowedEffects);
    

    其中data参数为要拖放的数据,allowedEffects表示要拖放的效果,可以是复制、拖放、链接等效果,DragDropEffects是枚举值,具体为

    public enum DragDropEffects
    {
        Scroll=int.MinValue, 
        All=-2147483645, 
        None=0, // 拖放目标不接受数据
        Copy=1, // 拖放源中的数据复制到放置目标
        Move=2, // 拖放源中的数据拖到放置目标
        Link=4;	// 拖动源中的数据链接到放置目标
    }
    

    当开始调用DoDragDrop方法拖动一个数据对象时,DoDragDrops在拖放过程中,检测当前光标位置下的控件是不是有效的放置目标。如果当前光标下的控件是有效的放置目标,则GiveFeedBack事件以指定的拖放效果引发。在检测当前位置光标是否为有效的拖放目标时,DoDragDrops方法同时跟踪光标位置,键盘状态和鼠标状态的更改。

    • 如果用于移出了一个窗口,则引发DragLeave事件

    • 如果移入了一个控件,则引发该控件的DragEnter事件

    • 如果鼠标移动,但是停留在一个控件中,则引发DragOver事件

    • 如果用一个有效的置放目标上放开鼠标按键,将会引发目标控件的DragDrop事件

    如果检测到更改了键盘或者鼠标状态,则引发拖放源的QueryContinueDrag事件, 并根据事件的QueryContinueDragEventArgs的Action属性值确定继续拖动,放置数据或取消操作

    • 如果Action属性指定为Continue,则将引发DragOver事件

    • 如果Action属性指定为Drop,则将放置效果返回给源,以便应用程序对数据进行适当的操作;例如,如果是移动操作,则剪切数据

    • 如果是DragAction的值为Cancel,则引发DragLeave事件

    示例代码

    private void listBox1_MouseDown(object sender, MouseEventArgs e)
    {
        // 如果listBox中的元素为0直接返回
        if (listBox1.Items.Count == 0)
            return;
        int index = listBox1.SelectedIndex;
        moveLayerIndex = index;
        // 如果鼠标点在空白处自己返回
        if (index < 0)
            return;
        string s = listBox1.Items[index].ToString();
        // 调用拖拽实现的方法-在本实验中依次触发DragEnter和DragDrop事件
        DragDropEffects dde = DoDragDrop(s, DragDropEffects.Move);
        
        // 如果是拖到上面,那么原来的位置为下移一层要删除,拖到下面,位置不变
        if (s == listBox1.Items[index].ToString())
            listBox1.Items.RemoveAt(index);
        else
            listBox1.Items.RemoveAt(index + 1);
    }
    
  2. 实现拖放效果-DragEnter,使用DragDropEffects枚举类型实现移动或复制等拖动效果

    通常我们会在使用GetDataPresent方法去检测所拖曳的数据格式是否适用于目标控件,并使用DragEventArgs类型参数的Effect属性来设定所允许的置放操作

    示例代码

    private void listBox1_DragEnter(object sender, DragEventArgs e)
    {
        //使用GetDataPresent方法来检查被拖曳的数据是否为纯文字(DataFormats.Text)
        //是的话将e.Effect属性设定为Move,否则设定为None表示不接受该数据
        if (e.Data.GetDataPresent(DataFormats.Text))
            e.Effect = DragDropEffects.Move;
        else
            e.Effect = DragDropEffects.None;
    }
    
  3. 实现放置数据操作,在目标控件上添加DragDrop响应代码,把数据添加到目标控件中

    也要先用GetDataPresent检查下数据源是不是字符串DataFormats.StringFormat,是的话执行后续的拖入操作

    中间的过程实现的是基于Arcgis Engine图层的拖拽效果,大家可以根据不同的需求完成

    示例代码

    private void listBox1_DragDrop(object sender, DragEventArgs e)
    {
        
        if(e.Data.GetDataPresent(DataFormats.StringFormat))
        {
            System.Drawing.Point point = listBox1.PointToClient(new System.Drawing.Point(e.X, e.Y));
            int index = listBox1.IndexFromPoint(point);
            if (index > -1)
            {
                MessageBox.Show("你将把" + e.Data.GetData(DataFormats.StringFormat) + "图层移动到" + listBox1.Items[index] + "之上");
                listBox1.Items.Insert(index, listBox1.SelectedItem);    // Insert是插在index之上
                axMapControl1.MoveLayerTo(moveLayerIndex, index);
            }
            else
            {
                MessageBox.Show("你将把" + e.Data.GetData(DataFormats.StringFormat) + "图层移动到最底层");
                listBox1.Items.Add(listBox1.SelectedItem);
                axMapControl1.MoveLayerTo(moveLayerIndex, axMapControl1.LayerCount-1);
            }
        }
    }
    

参考博客
C# DragDropEffects类与拖动实现
C# 拖放操作源码详解1

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
实现C#窗体的任意位置拖动效果,可以通过以下步骤进行: 1. 在窗体上添加一个Panel控件,并将其Dock属性设置为Top。这个Panel控件将作为窗体的标题栏。 2. 在Panel控件上添加一个Label或者其他控件,用来显示窗体的标题。 3. 在Panel控件的MouseDown事件中,获取鼠标当前的位置,并将窗体的Location属性设置为这个位置。同时设置一个变量记录鼠标按下时的位置。 4. 在Panel控件的MouseMove事件中,如果鼠标左键被按下,计算鼠标当前位置和按下时位置的偏移量,然后将窗体的Location属性加上这个偏移量。 下面是示例代码: ``` public partial class Form1 : Form { private Point mouseOffset; public Form1() { InitializeComponent(); } private void panelTitle_MouseDown(object sender, MouseEventArgs e) { mouseOffset = new Point(-e.X, -e.Y); this.Cursor = Cursors.SizeAll; } private void panelTitle_MouseMove(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { Point mousePos = Control.MousePosition; mousePos.Offset(mouseOffset.X, mouseOffset.Y); this.Location = mousePos; } } private void panelTitle_MouseUp(object sender, MouseEventArgs e) { this.Cursor = Cursors.Default; } } ``` 在上述代码中,panelTitle是我们添加的Panel控件,用来作为窗体的标题栏。在MouseDown事件中,我们记录鼠标按下时的位置,并将鼠标的光标设置为SizeAll,以便用户知道窗体可以被拖动。在MouseMove事件中,如果鼠标左键被按下,我们计算鼠标当前位置和按下时位置的偏移量,并将窗体的Location属性设置为鼠标当前位置加上偏移量。在MouseUp事件中,我们将光标设置回默认状态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

linengcs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值