Lets do a really simple sample, drag the text from a link label into a text box.  Once you understand this sample, you should pretty much be able to rock and roll on any drag/drop.

We're going to mouse down on the label and drag it over the text box.  Once released, the text of the label should copy into the textbox.

Step one: getting who's who straight. 

LinkLabel is our DragSource (the thing we clicked on which contains data we want somewhere else)
TextBox is our DragTarget (the thing that's going to get the new data)

Step two: getting the LinkLabel to initiate the drag

  • Add event handlers for the mouse down and the mouse move event.
  • In the MouseDown event, store off the initial location of the MouseDown.
  • In the MouseMove event, check to see if the mouse is down and has moved far enough that we should consider it a drag.
  • If the mouse has moved enough, we should call DoDragDrop passing the data we want to copy onto the clipboard, and a set of allowed effects.

Here's the code
                
private Point mouseDownLocation = Point.Empty;
            private void linkLabel1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) {
                mouseDownLocation = new Point(e.X, e.Y);
            }

            private void linkLabel1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) {
               
                if (e.Button == MouseButtons.Left) {
                    // we know the mouse is down - has it the mouse moved enough that we should
                    // consider it a drag?
                    Size dragBoxSize = SystemInformation.DragSize;

                    if ((dragBoxSize.Width > Math.Abs(mouseDownLocation.X - e.X))
                        ||(dragBoxSize.Height > Math.Abs(mouseDownLocation.Y - e.Y))) {
                        // we should consider this a drag...
                        linkLabel1.DoDragDrop(http://www.microsoft.com, DragDropEffects.Copy);

                    }
                }
            }


Step three: getting the TextBox to accept the drag

  • We want to register the TextBox as a thing that can accept drops, so we need to set textBox1.AllowDrop = true;
  • When the text is dragged into the TextBox (on DragEnter) we need to say that it is a valid drop by setting Effect = Copy
  • When the text is dragged over the TextBox (on DragOver) we need to say that it is a valid drop by setting Effect = Copy
  • When the text is dropped onto the TextBox, we need to copy the data out of the clipboard and into the textbox.

Add EventHandlers on the for DragEnter, DragOver, DragDrop and set AllowDrop = true
      
  private void textBox1_DragEnter(object sender, System.Windows.Forms.DragEventArgs e) {
            e.Effect = DragDropEffects.Copy;
        }

        private void textBox1_DragOver(object sender, System.Windows.Forms.DragEventArgs e) {
            e.Effect = DragDropEffects.Copy;       
        }

        private void textBox1_DragDrop(object sender, System.Windows.Forms.DragEventArgs e) {
            string text = e.Data.GetData(typeof(string)) as string;
            textBox1.Text += text;

        }

Step four: Run the app! 

Drag the linklabel over the textbox, and once you move into the textbox area, you'll see that the cursor switched from no smoking to the "copy" cursor.  If you go back and change all the AllowedEffects/Effects to move, the cursor will switch to the move cursor.  This is here to visually indicate to the user what they're doing by doing the drag - are they making a copy or are they moving the data to a new location.

Boom!  You've got Drag/Drop!  Are my five minutes up yet?

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace DragDropSample {
    /// <summary>
    /// Summary description for Form1.
    /// </summary>
    public class Form1 : System.Windows.Forms.Form {
        private System.Windows.Forms.LinkLabel linkLabel1;
        private System.Windows.Forms.TextBox textBox1;

        public Form1() {           
            InitializeComponent();      
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent() {
            this.linkLabel1 = new System.Windows.Forms.LinkLabel();
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.SuspendLayout();
            //
            // linkLabel1
            //
            this.linkLabel1.Location = new System.Drawing.Point(56, 40);
            this.linkLabel1.Name = "linkLabel1";
            this.linkLabel1.TabIndex = 0;
            this.linkLabel1.TabStop = true;
            this.linkLabel1.Text = "linkLabel1";
            this.linkLabel1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.linkLabel1_MouseMove);
            this.linkLabel1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.linkLabel1_MouseDown);
            //
            // textBox1
            //
            this.textBox1.AllowDrop = true;
            this.textBox1.Location = new System.Drawing.Point(56, 80);
            this.textBox1.Name = "textBox1";
            this.textBox1.TabIndex = 1;
            this.textBox1.Text = "textBox1";
            this.textBox1.DragOver += new System.Windows.Forms.DragEventHandler(this.textBox1_DragOver);
            this.textBox1.DragDrop += new System.Windows.Forms.DragEventHandler(this.textBox1_DragDrop);
            this.textBox1.DragEnter += new System.Windows.Forms.DragEventHandler(this.textBox1_DragEnter);
            //
            // Form1
            //
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(292, 266);
            this.Controls.Add(this.textBox1);
            this.Controls.Add(this.linkLabel1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);

        }
        #endregion

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

        #region LinkLabel as DropSource

        private Point mouseDownLocation = Point.Empty;
        private void linkLabel1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) {
            mouseDownLocation = new Point(e.X, e.Y);
        }

        private void linkLabel1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) {
               
            if (e.Button == MouseButtons.Left) {
                // we know the mouse is down - has it the mouse moved enough that we should
                // consider it a drag?
                Size dragBoxSize = SystemInformation.DragSize;

                if ((dragBoxSize.Width > Math.Abs(mouseDownLocation.X - e.X))
                    ||(dragBoxSize.Height > Math.Abs(mouseDownLocation.Y - e.Y))) {
                    // we should consider this a drag...
                    linkLabel1.DoDragDrop("
http://www.microsoft.com", DragDropEffects.Copy);

                }
            }
        }

        #endregion
        #region TextBox as DropTarget

        private void textBox1_DragEnter(object sender, System.Windows.Forms.DragEventArgs e) {
            e.Effect = DragDropEffects.Copy;                      
        }

        private void textBox1_DragOver(object sender, System.Windows.Forms.DragEventArgs e) {
            e.Effect = DragDropEffects.Copy;                      
        }

        private void textBox1_DragDrop(object sender, System.Windows.Forms.DragEventArgs e) {
            textBox1.Text = e.Data.GetData(typeof(string)) as string;
        }
        #endregion

    }
      
}

Ah.  Still here?  Good, we can take a deeper look at a few more details.


Step five:  Getting more picky about the data you get

TextBox is not really finished.  It's currently saying that any data whatsoever can be copied into it, which isn't exactly true. If someone had stored a bitmap onto the clipboard, it would have no way of displaying that.  So we have to get defensive here and not allow things it can't deal with.

This is handled by calling e.Data.GetDataPresent with our type to see if it's on the clipboard.
       
private void textBox1_DragEnter(object sender, System.Windows.Forms.DragEventArgs e) {
            if (e.Data.GetDataPresent(DataFormats.Text)) {
                e.Effect = DragDropEffects.Copy;           
            }
            else {
                e.Effect = DragDropEffects.None;
            }
        }

        private void textBox1_DragOver(object sender, System.Windows.Forms.DragEventArgs e) {
            if (e.Data.GetDataPresent(DataFormats.Text)) {
                e.Effect = DragDropEffects.Copy;           
            }
            else {
                e.Effect = DragDropEffects.None;
            }       
        }

        private void textBox1_DragDrop(object sender, System.Windows.Forms.DragEventArgs e) {
            if (e.Data.GetDataPresent(DataFormats.Text)) {
                string text = e.Data.GetData(typeof(string)) as string;
                textBox1.Text += text;
            }
        }

Step 6: putting richer data on the clipboard

Let's imagine we want to support dragging into rich text box AND text box.  Except when we drag into rich text box, we want to have a fancy link format

Sound hard?  Not really.

All you have to do is replace the call to DoDragDrop with a custom DataObject.  Each call to SetData adds an extra format that can be pulled off the clipboard.

    DataObject dataObject = new DataObject();
    dataObject.SetData(DataFormats.Rtf, false,@"{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fnil\fcharset0 Microsoft Sans Serif;}}\viewkind4\uc1\pard\f0\fs17
http://www.microsoft.com\par}" );
    dataObject.SetData(DataFormats.Text, "
http://www.microsoft.com");
    linkLabel1.DoDragDrop(dataObject, DragDropEffects.Copy);

The richtextbox drag handler would look something like this:

       private void richTextBox1_DragEnter(object sender, System.Windows.Forms.DragEventArgs e) {       
            if (e.Data.GetDataPresent(DataFormats.Text) || e.Data.GetDataPresent(DataFormats.Rtf)) {
                e.Effect = DragDropEffects.Copy;           
            }
            else {
                e.Effect = DragDropEffects.None;
            }
       }

          private void richTextBox1_DragOver(object sender, System.Windows.Forms.DragEventArgs e) {          
               if (e.Data.GetDataPresent(DataFormats.Text) || e.Data.GetDataPresent(DataFormats.Rtf)) {
                   e.Effect = DragDropEffects.Copy;            
              }
              else {
                   e.Effect = DragDropEffects.None;
               }
          }

And finally the DragDrop handler should now pull off RTF first, then Text.

      private void richTextBox1_DragDrop(object sender, System.Windows.Forms.DragEventArgs e) {
            RichTextBox rtb = sender as RichTextBox;
            if (e.Data.GetDataPresent(DataFormats.Rtf)) {
                // prefer to use the rich text in this case
               
                rtb.Rtf = e.Data.GetData(DataFormats.Rtf) as string;
            }
            if (e.Data.GetDataPresent(DataFormats.Text)) {
                string text = e.Data.GetData(typeof(string)) as string;
                rtb.Text = text;
            }

        }

There are some other details I'm skipping... like events that are called back on the DropSource.  Typically you dont need these, but they include QueryContinueDrag and GiveFeedback.  QueryContinueDrag lets the linklabel in our case cancel the drag.  GiveFeedback allows you to use custom cursors. 

If you've got a custom CLR type, you can also use that directly in the DataObject.  For example, you can put a ToolBarButton on the clipboard by stuffing it in the call to linkLabel.DoDragDrop(toolBarButton) - the DropTarget handlers need to look for this using the GetDataPresent(typeof(ToolBarButton)) overload instead of using one of the DataFormats.

For more information, check out the docs on this area.

 

Here's the entire sample with multiple formats + the rich text box.

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;

namespace DragDropSample {
    /// <summary>
    /// Summary description for Form1.
    /// </summary>
    public class Form1 : System.Windows.Forms.Form {
        private System.Windows.Forms.LinkLabel linkLabel1;
        private System.Windows.Forms.TextBox textBox1;
        private System.Windows.Forms.RichTextBox richTextBox1;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;

        public Form1() {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent();

            this.richTextBox1.DragOver += new System.Windows.Forms.DragEventHandler(this.textBox1_DragOver);
            this.richTextBox1.DragDrop += new System.Windows.Forms.DragEventHandler(this.textBox1_DragDrop);
            this.richTextBox1.DragEnter += new System.Windows.Forms.DragEventHandler(this.textBox1_DragEnter);
      

        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing ) {
            if( disposing ) {
                if (components != null) {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent() {
            this.linkLabel1 = new System.Windows.Forms.LinkLabel();
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.richTextBox1 = new System.Windows.Forms.RichTextBox();
            this.SuspendLayout();
            //
            // linkLabel1
            //
            this.linkLabel1.Location = new System.Drawing.Point(56, 40);
            this.linkLabel1.Name = "linkLabel1";
            this.linkLabel1.TabIndex = 0;
            this.linkLabel1.TabStop = true;
            this.linkLabel1.Text = "linkLabel1";
            this.linkLabel1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.linkLabel1_MouseMove);
            this.linkLabel1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.linkLabel1_MouseDown);
            //
            // textBox1
            //
            this.textBox1.AllowDrop = true;
            this.textBox1.Location = new System.Drawing.Point(56, 80);
            this.textBox1.Name = "textBox1";
            this.textBox1.TabIndex = 1;
            this.textBox1.Text = "textBox1";
            this.textBox1.DragOver += new System.Windows.Forms.DragEventHandler(this.textBox1_DragOver);
            this.textBox1.DragDrop += new System.Windows.Forms.DragEventHandler(this.textBox1_DragDrop);
            this.textBox1.DragEnter += new System.Windows.Forms.DragEventHandler(this.textBox1_DragEnter);
            //
            // richTextBox1
            //
            this.richTextBox1.AllowDrop = true;
            this.richTextBox1.Location = new System.Drawing.Point(56, 128);
            this.richTextBox1.Name = "richTextBox1";
            this.richTextBox1.TabIndex = 2;
            this.richTextBox1.Text = "richTextBox1";
            //
            // Form1
            //
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(292, 266);
            this.Controls.Add(this.richTextBox1);
            this.Controls.Add(this.textBox1);
            this.Controls.Add(this.linkLabel1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);

        }
        #endregion

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

        #region LinkLabel as DropSource

        private Point mouseDownLocation = Point.Empty;
        private void linkLabel1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) {
            mouseDownLocation = new Point(e.X, e.Y);
        }

        private void linkLabel1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) {
               
            if (e.Button == MouseButtons.Left) {
                // we know the mouse is down - has it the mouse moved enough that we should
                // consider it a drag?
                Size dragBoxSize = SystemInformation.DragSize;

                if ((dragBoxSize.Width > Math.Abs(mouseDownLocation.X - e.X))
                    ||(dragBoxSize.Height > Math.Abs(mouseDownLocation.Y - e.Y))) {
                    // we should consider this a drag...
                    DataObject dataObject = new DataObject();
                    dataObject.SetData(DataFormats.Rtf, false,@"{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fnil\fcharset0 Microsoft Sans Serif;}}\viewkind4\uc1\pard\f0\fs17
http://www.microsoft.com\par}" );
                    dataObject.SetData(DataFormats.Text, "
http://www.microsoft.com");
                    linkLabel1.DoDragDrop(dataObject, DragDropEffects.Copy);

                }
            }
        }

        #endregion
        #region TextBox and RichTextBox as DropTarget

        private void textBox1_DragEnter(object sender, System.Windows.Forms.DragEventArgs e) {
            if (e.Data.GetDataPresent(DataFormats.Text)) {
                e.Effect = DragDropEffects.Copy;           
            }
            else if (sender is RichTextBox &&e.Data.GetDataPresent(DataFormats.Rtf)) {
                e.Effect = DragDropEffects.Copy;
            }
            else {
                e.Effect = DragDropEffects.None;
            }
        }

        private void textBox1_DragOver(object sender, System.Windows.Forms.DragEventArgs e) {
            if (e.Data.GetDataPresent(DataFormats.Text)) {
                e.Effect = DragDropEffects.Copy;           
            }
            else if (sender is RichTextBox &&e.Data.GetDataPresent(DataFormats.Rtf)) {
                e.Effect = DragDropEffects.Copy;
            }
            else {
                e.Effect = DragDropEffects.None;
            }       
        }

        private void textBox1_DragDrop(object sender, System.Windows.Forms.DragEventArgs e) {
           
            if (sender is RichTextBox && e.Data.GetDataPresent(DataFormats.Rtf)) {
                // prefer to use the rich text in this case
                RichTextBox rtb = sender as RichTextBox;
                rtb.Rtf = e.Data.GetData(DataFormats.Rtf) as string;
            }
            if (e.Data.GetDataPresent(DataFormats.Text)) {
                string text = e.Data.GetData(typeof(string)) as string;
                Control textBox = sender as Control;
                if (textBox != null) {
                    textBox1.Text = text;
                }
            }

        }
        #endregion

    }