Control.DoDragDrop 方法

定义

重载

DoDragDrop(Object, DragDropEffects, Bitmap, Point, Boolean)

开始拖动操作。

C#
public System.Windows.Forms.DragDropEffects DoDragDrop (object data, System.Windows.Forms.DragDropEffects allowedEffects, System.Drawing.Bitmap? dragImage, System.Drawing.Point cursorOffset, bool useDefaultDragImage);

参数

data
Object
allowedEffects
DragDropEffects
dragImage
Bitmap
cursorOffset
Point
useDefaultDragImage
Boolean

返回

来自 DragDropEffects 枚举的值,表示拖放操作期间执行的最终效果。

注解

allowedEffects 参数确定可能发生哪些拖动操作。 如果拖动操作需要与其他进程中的应用程序互操作,data 应是实现 ISerializable的基托管类(StringBitmapMetafile)或某些实现 ISerializableObjectdata 也可以是实现 IDataObject的任何 ObjectdragImage 是将在拖动操作期间显示的位图,cursorOffset 指定光标在 dragImage中的位置,这是与左上角的偏移量。 为 useDefaultDragImage 指定 true,以使用大小为 96x96 的分层窗口拖动图像;否则 false。 请注意,如果图像宽度或高度超过 300 像素,则混合 dragImage 的外部边缘。

由于 DoDragDrop(Object, DragDropEffects, Bitmap, Point, Boolean) 在计算 alpha 值时始终执行 RGB 乘法步骤,因此应始终传递一个不带预乘 alpha 混合的 Bitmap。 传递具有预乘 alpha 混合的 Bitmap 不会产生任何错误,但此方法将再次相乘,从而将生成的 alpha 值加倍。

适用于

Windows Desktop 9 和其他版本
产品 版本
Windows Desktop 7, 8, 9

DoDragDrop(Object, DragDropEffects)

开始拖放操作。

C#
public System.Windows.Forms.DragDropEffects DoDragDrop (object data, System.Windows.Forms.DragDropEffects allowedEffects);

参数

data
Object

要拖动的数据。

allowedEffects
DragDropEffects

DragDropEffects 值之一。

返回

来自 DragDropEffects 枚举的值,表示拖放操作期间执行的最终效果。

示例

下面的代码示例演示两个 ListBox 控件之间的拖放操作。 该示例在拖动操作启动时调用 DoDragDrop 方法。 如果鼠标在 MouseDown 事件期间从鼠标位置移动了超过 SystemInformation.DragSize,则拖动操作将启动。 IndexFromPoint 方法用于确定在 MouseDown 事件期间要拖动的项的索引。

该示例还演示如何对拖放操作使用自定义游标。 该示例要求应用程序目录中分别存在两个游标文件(3dwarro.cur3dwno.cur),分别用于自定义拖放游标。 如果选中 UseCustomCursorsCheckCheckBox,将使用自定义游标。 自定义游标在 GiveFeedback 事件处理程序中设置。

键盘状态在右侧 ListBoxDragOver 事件处理程序中计算,以确定拖动操作将基于 SHIFT、Ctrl、Alt 或 Ctrl+Alt 键的状态。 在 DragOver 事件期间,也会确定 ListBox 发生放置的位置。 如果要删除的数据不是 String,则 DragEventArgs.Effect 设置为 DragDropEffects中的 None。 最后,删除状态显示在 DropLocationLabelLabel中。

要删除的右 ListBox 的数据在 DragDrop 事件处理程序中确定,并在 ListBox的适当位置添加 String 值。 如果拖动操作在窗体边界之外移动,则拖放操作在 QueryContinueDrag 事件处理程序中取消。

C#
using System;
using System.Drawing;
using System.Windows.Forms;

namespace Snip_DragNDrop
{
    public class Form1 : Form
    {
        private ListBox ListDragSource;
        private ListBox ListDragTarget;
        private CheckBox UseCustomCursorsCheck;
        private Label DropLocationLabel;

        private int indexOfItemUnderMouseToDrag;
        private int indexOfItemUnderMouseToDrop;

        private Rectangle dragBoxFromMouseDown;
        private Point screenOffset;

        private Cursor MyNoDropCursor;
        private Cursor MyNormalCursor;

        // The main entry point for the application.
        [STAThread]
        static void Main()
        {
            Application.Run(new Form1());
        }

        public Form1()
        {
            this.ListDragSource = new ListBox();
            this.ListDragTarget = new ListBox();
            this.UseCustomCursorsCheck = new CheckBox();
            this.DropLocationLabel = new Label();

            this.SuspendLayout();

            // ListDragSource
            this.ListDragSource.Items.AddRange(new object[] {"one", "two", "three", "four",
                                                             "five", "six", "seven", "eight",
                                                             "nine", "ten"});
            this.ListDragSource.Location = new Point(10, 17);
            this.ListDragSource.Size = new Size(120, 225);
            this.ListDragSource.MouseDown += this.ListDragSource_MouseDown;
            this.ListDragSource.QueryContinueDrag += this.ListDragSource_QueryContinueDrag;
            this.ListDragSource.MouseUp += this.ListDragSource_MouseUp;
            this.ListDragSource.MouseMove += this.ListDragSource_MouseMove;
            this.ListDragSource.GiveFeedback += this.ListDragSource_GiveFeedback;

            // ListDragTarget
            this.ListDragTarget.AllowDrop = true;
            this.ListDragTarget.Location = new Point(154, 17);
            this.ListDragTarget.Size = new Size(120, 225);
            this.ListDragTarget.DragOver += this.ListDragTarget_DragOver;
            this.ListDragTarget.DragDrop += this.ListDragTarget_DragDrop;
            this.ListDragTarget.DragEnter += this.ListDragTarget_DragEnter;
            this.ListDragTarget.DragLeave += this.ListDragTarget_DragLeave;

            // UseCustomCursorsCheck
            this.UseCustomCursorsCheck.Location = new Point(10, 243);
            this.UseCustomCursorsCheck.Size = new Size(137, 24);
            this.UseCustomCursorsCheck.Text = "Use Custom Cursors";

            // DropLocationLabel
            this.DropLocationLabel.Location = new Point(154, 245);
            this.DropLocationLabel.Size = new Size(137, 24);
            this.DropLocationLabel.Text = "None";

            // Form1
            this.ClientSize = new Size(292, 270);
            this.Controls.AddRange(new Control[] {
                this.ListDragSource,
                this.ListDragTarget,
                this.UseCustomCursorsCheck,
                this.DropLocationLabel});
            this.Text = "drag-and-drop Example";

            this.ResumeLayout(false);
        }

        private void ListDragSource_MouseDown(object sender, MouseEventArgs e)
        {
            // Get the index of the item the mouse is below.
            indexOfItemUnderMouseToDrag = ListDragSource.IndexFromPoint(e.X, e.Y);

            if (indexOfItemUnderMouseToDrag != ListBox.NoMatches)
            {
                // Remember the point where the mouse down occurred. The DragSize indicates
                // the size that the mouse can move before a drag event should be started.
                Size dragSize = SystemInformation.DragSize;

                // Create a rectangle using the DragSize, with the mouse position being
                // at the center of the rectangle.
                dragBoxFromMouseDown = new Rectangle(
                    new Point(e.X - (dragSize.Width / 2),
                              e.Y - (dragSize.Height / 2)),
                    dragSize);
            }
            else
            {
                // Reset the rectangle if the mouse is not over an item in the ListBox.
                dragBoxFromMouseDown = Rectangle.Empty;
            }
        }

        private void ListDragSource_MouseUp(object sender, MouseEventArgs e)
        {
            // Reset the drag rectangle when the mouse button is raised.
            dragBoxFromMouseDown = Rectangle.Empty;
        }

        private void ListDragSource_MouseMove(object sender, MouseEventArgs e)
        {
            if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
            {
                // If the mouse moves outside the rectangle, start the drag.
                if (dragBoxFromMouseDown != Rectangle.Empty &&
                    !dragBoxFromMouseDown.Contains(e.X, e.Y))
                {
                    // Create custom cursors for the drag-and-drop operation.
                    try
                    {
                        MyNormalCursor = new Cursor("3dwarro.cur");
                        MyNoDropCursor = new Cursor("3dwno.cur");
                    }
                    catch
                    {
                        // An error occurred while attempting to load the cursors, so use
                        // standard cursors.
                        UseCustomCursorsCheck.Checked = false;
                    }
                    finally
                    {
                        // The screenOffset is used to account for any desktop bands 
                        // that may be at the top or left side of the screen when 
                        // determining when to cancel the drag drop operation.
                        screenOffset = SystemInformation.WorkingArea.Location;

                        // Proceed with the drag-and-drop, passing in the list item.
                        DragDropEffects dropEffect = ListDragSource.DoDragDrop(ListDragSource.Items[indexOfItemUnderMouseToDrag], DragDropEffects.All | DragDropEffects.Link);

                        // If the drag operation was a move then remove the item.
                        if (dropEffect == DragDropEffects.Move)
                        {
                            ListDragSource.Items.RemoveAt(indexOfItemUnderMouseToDrag);

                            // Selects the previous item in the list as long as the list has an item.
                            if (indexOfItemUnderMouseToDrag > 0)
                                ListDragSource.SelectedIndex = indexOfItemUnderMouseToDrag - 1;

                            else if (ListDragSource.Items.Count > 0)
                                // Selects the first item.
                                ListDragSource.SelectedIndex = 0;
                        }

                        // Dispose of the cursors since they are no longer needed.
                        if (MyNormalCursor != null)
                            MyNormalCursor.Dispose();

                        if (MyNoDropCursor != null)
                            MyNoDropCursor.Dispose();
                    }
                }
            }
        }
        private void ListDragSource_GiveFeedback(object sender, GiveFeedbackEventArgs e)
        {
            // Use custom cursors if the check box is checked.
            if (UseCustomCursorsCheck.Checked)
            {
                // Sets the custom cursor based upon the effect.
                e.UseDefaultCursors = false;
                if ((e.Effect & DragDropEffects.Move) == DragDropEffects.Move)
                    Cursor.Current = MyNormalCursor;
                else
                    Cursor.Current = MyNoDropCursor;
            }
        }
        private void ListDragTarget_DragOver(object sender, DragEventArgs e)
        {
            // Determine whether string data exists in the drop data. If not, then
            // the drop effect reflects that the drop cannot occur.
            if (!e.Data.GetDataPresent(typeof(System.String)))
            {
                e.Effect = DragDropEffects.None;
                DropLocationLabel.Text = "None - no string data.";
                return;
            }

            // Set the effect based upon the KeyState.
            if ((e.KeyState & (8 + 32)) == (8 + 32) &&
                (e.AllowedEffect & DragDropEffects.Link) == DragDropEffects.Link)
            {
                // KeyState 8 + 32 = CTRL + ALT

                // Link drag-and-drop effect.
                e.Effect = DragDropEffects.Link;
            }
            else if ((e.KeyState & 32) == 32 &&
                (e.AllowedEffect & DragDropEffects.Link) == DragDropEffects.Link)
            {
                // ALT KeyState for link.
                e.Effect = DragDropEffects.Link;
            }
            else if ((e.KeyState & 4) == 4 &&
                (e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move)
            {
                // SHIFT KeyState for move.
                e.Effect = DragDropEffects.Move;
            }
            else if ((e.KeyState & 8) == 8 &&
                (e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy)
            {
                // CTRL KeyState for copy.
                e.Effect = DragDropEffects.Copy;
            }
            else if ((e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move)
            {
                // By default, the drop action should be move, if allowed.
                e.Effect = DragDropEffects.Move;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }

            // Get the index of the item the mouse is below. 

            // The mouse locations are relative to the screen, so they must be 
            // converted to client coordinates.

            indexOfItemUnderMouseToDrop =
                ListDragTarget.IndexFromPoint(ListDragTarget.PointToClient(new Point(e.X, e.Y)));

            // Updates the label text.
            if (indexOfItemUnderMouseToDrop != ListBox.NoMatches)
            {
                DropLocationLabel.Text = "Drops before item #" + (indexOfItemUnderMouseToDrop + 1);
            }
            else
            {
                DropLocationLabel.Text = "Drops at the end.";
            }
        }
        private void ListDragTarget_DragDrop(object sender, DragEventArgs e)
        {
            // Ensure that the list item index is contained in the data.
            if (e.Data.GetDataPresent(typeof(System.String)))
            {
                Object item = e.Data.GetData(typeof(System.String));

                // Perform drag-and-drop, depending upon the effect.
                if (e.Effect == DragDropEffects.Copy ||
                    e.Effect == DragDropEffects.Move)
                {
                    // Insert the item.
                    if (indexOfItemUnderMouseToDrop != ListBox.NoMatches)
                        ListDragTarget.Items.Insert(indexOfItemUnderMouseToDrop, item);
                    else
                        ListDragTarget.Items.Add(item);
                }
            }
            // Reset the label text.
            DropLocationLabel.Text = "None";
        }
        private void ListDragSource_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
        {
            // Cancel the drag if the mouse moves off the form.
            ListBox lb = sender as ListBox;

            if (lb != null)
            {
                Form f = lb.FindForm();

                // Cancel the drag if the mouse moves off the form. The screenOffset
                // takes into account any desktop bands that may be at the top or left
                // side of the screen.
                if (((Control.MousePosition.X - screenOffset.X) < f.DesktopBounds.Left) ||
                    ((Control.MousePosition.X - screenOffset.X) > f.DesktopBounds.Right) ||
                    ((Control.MousePosition.Y - screenOffset.Y) < f.DesktopBounds.Top) ||
                    ((Control.MousePosition.Y - screenOffset.Y) > f.DesktopBounds.Bottom))
                {
                    e.Action = DragAction.Cancel;
                }
            }
        }
        private void ListDragTarget_DragEnter(object sender, DragEventArgs e)
        {
            // Reset the label text.
            DropLocationLabel.Text = "None";
        }
        private void ListDragTarget_DragLeave(object sender, EventArgs e)
        {
            // Reset the label text.
            DropLocationLabel.Text = "None";
        }
    }
}

下面的代码示例演示如何使用 DragDropEffects 枚举来指定如何在拖放操作所涉及的控件之间传输数据。 此示例要求窗体包含 RichTextBox 控件和 ListBox 控件,并且 ListBox 控件填充了有效文件名的列表。 当用户将文件名拖到 RichTextBox 控件上时,将引发控件的 DragEnter 事件。 在事件处理程序中,DragEventArgsEffect 属性初始化为 DragDropEffects,以指示文件路径引用的数据应复制到 RichTextBox 控件。

C#
private void Form1_Load(object sender, EventArgs e) 
{
   // Sets the AllowDrop property so that data can be dragged onto the control.
   richTextBox1.AllowDrop = true;

   // Add code here to populate the ListBox1 with paths to text files.
}

private void listBox1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
   // Determines which item was selected.
   ListBox lb =( (ListBox)sender);
   Point pt = new Point(e.X,e.Y);
   int index = lb.IndexFromPoint(pt);

   // Starts a drag-and-drop operation with that item.
   if(index>=0) 
   {
      lb.DoDragDrop(lb.Items[index].ToString(), DragDropEffects.Link);
   }
}

private void richTextBox1_DragEnter(object sender, DragEventArgs e) 
{
   // If the data is text, copy the data to the RichTextBox control.
   if(e.Data.GetDataPresent("Text"))
      e.Effect = DragDropEffects.Copy;
}

private void richTextBox1_DragDrop(object sender, DragEventArgs e) 
{
   // Loads the file into the control. 
   richTextBox1.LoadFile((String)e.Data.GetData("Text"), System.Windows.Forms.RichTextBoxStreamType.RichText);
}

注解

allowedEffects 参数确定可能发生哪些拖动操作。 如果拖动操作需要与其他进程中的应用程序进行互操作,则数据应为基托管类(StringBitmapMetafile),或者实现 ISerializableIDataObject的对象。

下面介绍了如何以及何时引发与拖放操作相关的事件。

DoDragDrop 方法确定当前光标位置下的控件。 然后检查控件是否为有效的删除目标。

如果控件是有效的放置目标,则会使用指定的拖放效果引发 GiveFeedback 事件。 有关拖放效果的列表,请参阅 DragDropEffects 枚举。

跟踪鼠标光标位置、键盘状态和鼠标按钮状态的更改。

  • 如果用户移出窗口,将引发 DragLeave 事件。

  • 如果鼠标进入另一个控件,则会引发该控件的 DragEnter

  • 如果鼠标移动但保留在同一控件中,则会引发 DragOver 事件。

如果键盘或鼠标按钮状态发生更改,则会引发 QueryContinueDrag 事件,并确定是继续拖动、删除数据,还是根据事件 QueryContinueDragEventArgsAction 属性的值取消操作。

  • 如果 DragAction 的值 Continue,则会引发 DragOver 事件以继续操作,并引发具有新效果的 GiveFeedback 事件,以便可以设置适当的视觉反馈。 有关有效删除效果的列表,请参阅 DragDropEffects 枚举。

    备注

    DragOverGiveFeedback 事件配对,以便在鼠标在放置目标之间移动时,系统会向用户提供鼠标位置的 up-to日期反馈。

  • 如果 DragAction 的值 Drop,则下降效果值将返回到源,以便源应用程序可以对源数据执行适当的操作;例如,如果操作是移动,则剪切数据。

  • 如果 DragAction 的值 Cancel,则会引发 DragLeave 事件。

备注

DoDragDrop 方法捕获所有异常,并仅重新引发以下安全或关键异常:

  • SecurityException

  • NullReferenceException

  • StackOverflowException

  • OutOfMemoryException

  • ThreadAbortException

  • ExecutionEngineException

  • IndexOutOfRangeException

  • AccessViolationException

另请参阅

适用于

.NET Framework 4.8.1 和其他版本
产品 版本
.NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
Windows Desktop 3.0, 3.1, 5, 6, 7, 8, 9