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 應該是基底 Managed 類別(StringBitmapMetafile),或實作 ISerializable的一些 Objectdata 也可以是實作 IDataObject的任何 ObjectdragImage 是在拖曳作業期間顯示的點陣圖,cursorOffset 指定游標在 dragImage內的位置,這是左上角的位移。 為 useDefaultDragImage 指定 true,以使用大小為96x96的分層視窗拖曳影像;否則 false。 請注意,如果影像寬度或高度超過 300 像素,則會混合 dragImage 的外部邊緣。

由於 DoDragDrop(Object, DragDropEffects, Bitmap, Point, Boolean) 在計算 Alpha 值時一律會執行 RGB 乘法步驟,因此您應該一律傳遞 Bitmap,而不需預乘 Alpha 混合。 不會因為傳遞具有預乘 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 事件處理程式中,且 String 值會在 ListBox的適當位置新增。 如果拖曳作業在窗體界限之外移動,則會在 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 參數會決定可以執行哪些拖曳作業。 如果拖曳作業需要與其他進程中的應用程式互操作,則數據應該是基底 Managed 類別(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