Walkthrough: Enabling Drag and Drop on a User Control

This walkthrough demonstrates how to create a custom user control that can participate in drag-and-drop data transfer in Windows Presentation Foundation (WPF).

In this walkthrough, you will create a custom WPF UserControl that represents a circle shape. You will implement functionality on the control to enable data transfer through drag-and-drop. For example, if you drag from one Circle control to another, the Fill color data is copied from the source Circle to the target. If you drag from a Circle control to a TextBox, the string representation of the Fill color is copied to the TextBox. You will also create a small application that contains two panel controls and a TextBox to test the drag-and-drop functionality. You will write code that enables the panels to process dropped Circle data, which will enable you to move or copy Circles from the Children collection of one panel to the other.

This walkthrough illustrates the following tasks:

  • Create a custom user control.

  • Enable the user control to be a drag source.

  • Enable the user control to be a drop target.

  • Enable a panel to receive data dropped from the user control.

Prerequisites

You need Visual Studio to complete this walkthrough.

Create the Application Project

In this section, you will create the application infrastructure, which includes a main page with two panels and a TextBox.

  1. Create a new WPF Application project in Visual Basic or Visual C# named DragDropExample. For more information, see Walkthrough: My first WPF desktop application.

  2. Open MainWindow.xaml.

  3. Add the following markup between the opening and closing Grid tags.

    This markup creates the user interface for the test application.

    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <StackPanel Grid.Column="0"
                Background="Beige">
        <TextBox Width="Auto" Margin="2"
                 Text="green"/>
    </StackPanel>
    <StackPanel Grid.Column="1"
                Background="Bisque">
    </StackPanel>
    

Add a New User Control to the Project

In this section, you will add a new user control to the project.

  1. On the Project menu, select Add User Control.

  2. In the Add New Item dialog box, change the name to Circle.xaml, and click Add.

    Circle.xaml and its code-behind is added to the project.

  3. Open Circle.xaml.

    This file will contain the user interface elements of the user control.

  4. Add the following markup to the root Grid to create a simple user control that has a blue circle as its UI.

    <Ellipse x:Name="circleUI" 
             Height="100" Width="100"
             Fill="Blue" />
    
  5. Open Circle.xaml.cs or Circle.xaml.vb.

  6. In C#, add the following code after the parameterless constructor to create a copy constructor. In Visual Basic, add the following code to create both a parameterless constructor and a copy constructor.

    In order to allow the user control to be copied, you add a copy constructor method in the code-behind file. In the simplified Circle user control, you will only copy the Fill and the size of the of the user control.

    public Circle(Circle c)
    {
        InitializeComponent();
        this.circleUI.Height = c.circleUI.Height;
        this.circleUI.Width = c.circleUI.Height;
        this.circleUI.Fill = c.circleUI.Fill;
    }
    
    Public Sub New()
        ' This call is required by the designer.
        InitializeComponent()
    End Sub
    
    Public Sub New(ByVal c As Circle)
        InitializeComponent()
        Me.circleUI.Height = c.circleUI.Height
        Me.circleUI.Width = c.circleUI.Height
        Me.circleUI.Fill = c.circleUI.Fill
    End Sub
    

Add the user control to the main window

  1. Open MainWindow.xaml.

  2. Add the following XAML to the opening Window tag to create an XML namespace reference to the current application.

    xmlns:local="clr-namespace:DragDropExample"
    
  3. In the first StackPanel, add the following XAML to create two instances of the Circle user control in the first panel.

    <local:Circle Margin="2" />
    <local:Circle Margin="2" />
    

    The full XAML for the panel looks like the following.

    <StackPanel Grid.Column="0"
                Background="Beige">
        <TextBox Width="Auto" Margin="2"
                 Text="green"/>
        <local:Circle Margin="2" />
        <local:Circle Margin="2" />
    </StackPanel>
    <StackPanel Grid.Column="1"
                Background="Bisque">
    </StackPanel>
    

Implement Drag Source Events in the User Control

In this section, you will override the OnMouseMove method and initiate the drag-and-drop operation.

If a drag is started (a mouse button is pressed and the mouse is moved), you will package the data to be transferred into a DataObject. In this case, the Circle control will package three data items; a string representation of its Fill color, a double representation of its height, and a copy of itself.

To initiate a drag-and-drop operation

  1. Open Circle.xaml.cs or Circle.xaml.vb.

  2. Add the following OnMouseMove override to provide class handling for the MouseMove event.

    protected override void OnMouseMove(MouseEventArgs e)
    {
        base.OnMouseMove(e);
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            // Package the data.
            DataObject data = new DataObject();
            data.SetData(DataFormats.StringFormat, circleUI.Fill.ToString());
            data.SetData("Double", circleUI.Height);
            data.SetData("Object", this);
    
            // Initiate the drag-and-drop operation.
            DragDrop.DoDragDrop(this, data, DragDropEffects.Copy | DragDropEffects.Move);
        }
    }
    
    Protected Overrides Sub OnMouseMove(ByVal e As System.Windows.Input.MouseEventArgs)
        MyBase.OnMouseMove(e)
        If e.LeftButton = MouseButtonState.Pressed Then
            ' Package the data.
            Dim data As New DataObject
            data.SetData(DataFormats.StringFormat, circleUI.Fill.ToString())
            data.SetData("Double", circleUI.Height)
            data.SetData("Object", Me)
    
            ' Inititate the drag-and-drop operation.
            DragDrop.DoDragDrop(Me, data, DragDropEffects.Copy Or DragDropEffects.Move)
        End If
    End Sub
    

    This OnMouseMove override performs the following tasks:

    • Checks whether the left mouse button is pressed while the mouse is moving.

    • Packages the Circle data into a DataObject. In this case, the Circle control packages three data items; a string representation of its Fill color, a double representation of its height, and a copy of itself.

    • Calls the static DragDrop.DoDragDrop method to initiate the drag-and-drop operation. You pass the following three parameters to the DoDragDrop method:

      • dragSource – A reference to this control.

      • data – The DataObject created in the previous code.

      • allowedEffects – The allowed drag-and-drop operations, which are Copy or Move.

  3. Press F5 to build and run the application.

  4. Click one of the Circle controls and drag it over the panels, the other Circle, and the TextBox. When dragging over the TextBox, the cursor changes to indicate a move.

  5. While dragging a Circle over the TextBox, press the Ctrl key. Notice how the cursor changes to indicate a copy.

  6. Drag and drop a Circle onto the TextBox. The string representation of the Circle’s fill color is appended to the TextBox.

    String representation of Circle's fill color

By default, the cursor will change during a drag-and-drop operation to indicate what effect dropping the data will have. You can customize the feedback given to the user by handling the GiveFeedback event and setting a different cursor.

Give feedback to the user

  1. Open Circle.xaml.cs or Circle.xaml.vb.

  2. Add the following OnGiveFeedback override to provide class handling for the GiveFeedback event.

    protected override void OnGiveFeedback(GiveFeedbackEventArgs e)
    {
        base.OnGiveFeedback(e);
        // These Effects values are set in the drop target's
        // DragOver event handler.
        if (e.Effects.HasFlag(DragDropEffects.Copy))
        {
            Mouse.SetCursor(Cursors.Cross);
        }
        else if (e.Effects.HasFlag(DragDropEffects.Move))
        {
            Mouse.SetCursor(Cursors.Pen);
        }
        else
        {
            Mouse.SetCursor(Cursors.No);
        }
        e.Handled = true;
    }
    
    Protected Overrides Sub OnGiveFeedback(ByVal e As System.Windows.GiveFeedbackEventArgs)
        MyBase.OnGiveFeedback(e)
        ' These Effects values are set in the drop target's
        ' DragOver event handler.
        If e.Effects.HasFlag(DragDropEffects.Copy) Then
            Mouse.SetCursor(Cursors.Cross)
        ElseIf e.Effects.HasFlag(DragDropEffects.Move) Then
            Mouse.SetCursor(Cursors.Pen)
        Else
            Mouse.SetCursor(Cursors.No)
        End If
        e.Handled = True
    End Sub
    

    This OnGiveFeedback override performs the following tasks:

    • Checks the Effects values that are set in the drop target's DragOver event handler.

    • Sets a custom cursor based on the Effects value. The cursor is intended to give visual feedback to the user about what effect dropping the data will have.

  3. Press F5 to build and run the application.

  4. Drag one of the Circle controls over the panels, the other Circle, and the TextBox. Notice that the cursors are now the custom cursors that you specified in the OnGiveFeedback override.

    Drag and drop with custom cursors

  5. Select the text green from the TextBox.

  6. Drag the green text to a Circle control. Notice that the default cursors are shown to indicate the effects of the drag-and-drop operation. The feedback cursor is always set by the drag source.

Implement Drop Target Events in the User Control

In this section, you will specify that the user control is a drop target, override the methods that enable the user control to be a drop target, and process the data that is dropped on it.

To enable the user control to be a drop target

  1. Open Circle.xaml.

  2. In the opening UserControl tag, add the AllowDrop property and set it to true.

    <UserControl x:Class="DragDropWalkthrough.Circle"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300"
                 AllowDrop="True">
    

The OnDrop method is called when the AllowDrop property is set to true and data from the drag source is dropped on the Circle user control. In this method, you will process the data that was dropped and apply the data to the Circle.

To process the dropped data

  1. Open Circle.xaml.cs or Circle.xaml.vb.

  2. Add the following OnDrop override to provide class handling for the Drop event.

    protected override void OnDrop(DragEventArgs e)
    {
        base.OnDrop(e);
    
        // If the DataObject contains string data, extract it.
        if (e.Data.GetDataPresent(DataFormats.StringFormat))
        {
            string dataString = (string)e.Data.GetData(DataFormats.StringFormat);
    
            // If the string can be converted into a Brush,
            // convert it and apply it to the ellipse.
            BrushConverter converter = new BrushConverter();
            if (converter.IsValid(dataString))
            {
                Brush newFill = (Brush)converter.ConvertFromString(dataString);
                circleUI.Fill = newFill;
    
                // Set Effects to notify the drag source what effect
                // the drag-and-drop operation had.
                // (Copy if CTRL is pressed; otherwise, move.)
                if (e.KeyStates.HasFlag(DragDropKeyStates.ControlKey))
                {
                    e.Effects = DragDropEffects.Copy;
                }
                else
                {
                    e.Effects = DragDropEffects.Move;
                }
            }
        }
        e.Handled = true;
    }
    
    Protected Overrides Sub OnDrop(ByVal e As System.Windows.DragEventArgs)
        MyBase.OnDrop(e)
        ' If the DataObject contains string data, extract it.
        If e.Data.GetDataPresent(DataFormats.StringFormat) Then
            Dim dataString As String = e.Data.GetData(DataFormats.StringFormat)
    
            ' If the string can be converted into a Brush, 
            ' convert it and apply it to the ellipse.
            Dim converter As New BrushConverter
            If converter.IsValid(dataString) Then
                Dim newFill As Brush = converter.ConvertFromString(dataString)
                circleUI.Fill = newFill
    
                ' Set Effects to notify the drag source what effect
                ' the drag-and-drop operation had.
                ' (Copy if CTRL is pressed; otherwise, move.)
                If e.KeyStates.HasFlag(DragDropKeyStates.ControlKey) Then
                    e.Effects = DragDropEffects.Copy
                Else
                    e.Effects = DragDropEffects.Move
                End If
            End If
        End If
        e.Handled = True
    End Sub
    

    This OnDrop override performs the following tasks:

    • Uses the GetDataPresent method to check if the dragged data contains a string object.

    • Uses the GetData method to extract the string data if it is present.

    • Uses a BrushConverter to try to convert the string to a Brush.

    • If the conversion is successful, applies the brush to the Fill of the Ellipse that provides the UI of the Circle control.

    • Marks the Drop event as handled. You should mark the drop event as handled so that other elements that receive this event know that the Circle user control handled it.

  3. Press F5 to build and run the application.

  4. Select the text green in the TextBox.

  5. Drag the text to a Circle control and drop it. The Circle changes from blue to green.

    Convert a string to a brush

  6. Type the text green in the TextBox.

  7. Select the text gre in the TextBox.

  8. Drag it to a Circle control and drop it. Notice that the cursor changes to indicate that the drop is allowed, but the color of the Circle does not change because gre is not a valid color.

  9. Drag from the green Circle control and drop on the blue Circle control. The Circle changes from blue to green. Notice that which cursor is shown depends on whether the TextBox or the Circle is the drag source.

Setting the AllowDrop property to true and processing the dropped data is all that is required to enable an element to be a drop target. However, to provide a better user experience, you should also handle the DragEnter, DragLeave, and DragOver events. In these events, you can perform checks and provide additional feedback to the user before the data is dropped.

When data is dragged over the Circle user control, the control should notify the drag source whether it can process the data that is being dragged. If the control does not know how to process the data, it should refuse the drop. To do this, you will handle the DragOver event and set the Effects property.

To verify that the data drop is allowed

  1. Open Circle.xaml.cs or Circle.xaml.vb.

  2. Add the following OnDragOver override to provide class handling for the DragOver event.

    protected override void OnDragOver(DragEventArgs e)
    {
        base.OnDragOver(e);
        e.Effects = DragDropEffects.None;
    
        // If the DataObject contains string data, extract it.
        if (e.Data.GetDataPresent(DataFormats.StringFormat))
        {
            string dataString = (string)e.Data.GetData(DataFormats.StringFormat);
    
            // If the string can be converted into a Brush, allow copying or moving.
            BrushConverter converter = new BrushConverter();
            if (converter.IsValid(dataString))
            {
                // Set Effects to notify the drag source what effect
                // the drag-and-drop operation will have. These values are
                // used by the drag source's GiveFeedback event handler.
                // (Copy if CTRL is pressed; otherwise, move.)
                if (e.KeyStates.HasFlag(DragDropKeyStates.ControlKey))
                {
                    e.Effects = DragDropEffects.Copy;
                }
                else
                {
                    e.Effects = DragDropEffects.Move;
                }
            }
        }
        e.Handled = true;
    }
    
    Protected Overrides Sub OnDragOver(ByVal e As System.Windows.DragEventArgs)
        MyBase.OnDragOver(e)
        e.Effects = DragDropEffects.None
    
        ' If the DataObject contains string data, extract it.
        If e.Data.GetDataPresent(DataFormats.StringFormat) Then
            Dim dataString As String = e.Data.GetData(DataFormats.StringFormat)
    
            ' If the string can be converted into a Brush, allow copying or moving.
            Dim converter As New BrushConverter
            If converter.IsValid(dataString) Then
                ' Set Effects to notify the drag source what effect
                ' the drag-and-drop operation will have. These values are 
                ' used by the drag source's GiveFeedback event handler.
                ' (Copy if CTRL is pressed; otherwise, move.)
                If e.KeyStates.HasFlag(DragDropKeyStates.ControlKey) Then
                    e.Effects = DragDropEffects.Copy
                Else
                    e.Effects = DragDropEffects.Move
                End If
            End If
        End If
        e.Handled = True
    End Sub
    

    This OnDragOver override performs the following tasks:

    • Sets the Effects property to None.

    • Performs the same checks that are performed in the OnDrop method to determine whether the Circle user control can process the dragged data.

    • If the user control can process the data, sets the Effects property to Copy or Move.

  3. Press F5 to build and run the application.

  4. Select the text gre in the TextBox.

  5. Drag the text to a Circle control. Notice that the cursor now changes to indicate that the drop is not allowed because gre is not a valid color.

You can further enhance the user experience by applying a preview of the drop operation. For the Circle user control, you will override the OnDragEnter and OnDragLeave methods. When the data is dragged over the control, the current background Fill is saved in a placeholder variable. The string is then converted to a brush and applied to the Ellipse that provides the Circle's UI. If the data is dragged out of the Circle without being dropped, the original Fill value is re-applied to the Circle.

To preview the effects of the drag-and-drop operation

  1. Open Circle.xaml.cs or Circle.xaml.vb.

  2. In the Circle class, declare a private Brush variable named _previousFill and initialize it to null.

    public partial class Circle : UserControl
    {
        private Brush _previousFill = null;
    
    Public Class Circle
        Private _previousFill As Brush = Nothing
    
  3. Add the following OnDragEnter override to provide class handling for the DragEnter event.

    protected override void OnDragEnter(DragEventArgs e)
    {
        base.OnDragEnter(e);
        // Save the current Fill brush so that you can revert back to this value in DragLeave.
        _previousFill = circleUI.Fill;
    
        // If the DataObject contains string data, extract it.
        if (e.Data.GetDataPresent(DataFormats.StringFormat))
        {
            string dataString = (string)e.Data.GetData(DataFormats.StringFormat);
    
            // If the string can be converted into a Brush, convert it.
            BrushConverter converter = new BrushConverter();
            if (converter.IsValid(dataString))
            {
                Brush newFill = (Brush)converter.ConvertFromString(dataString.ToString());
                circleUI.Fill = newFill;
            }
        }
    }
    
    Protected Overrides Sub OnDragEnter(ByVal e As System.Windows.DragEventArgs)
        MyBase.OnDragEnter(e)
        _previousFill = circleUI.Fill
    
        ' If the DataObject contains string data, extract it.
        If e.Data.GetDataPresent(DataFormats.StringFormat) Then
            Dim dataString As String = e.Data.GetData(DataFormats.StringFormat)
    
            ' If the string can be converted into a Brush, convert it.
            Dim converter As New BrushConverter
            If converter.IsValid(dataString) Then
                Dim newFill As Brush = converter.ConvertFromString(dataString)
                circleUI.Fill = newFill
            End If
        End If
        e.Handled = True
    End Sub
    

    This OnDragEnter override performs the following tasks:

    • Saves the Fill property of the Ellipse in the _previousFill variable.

    • Performs the same checks that are performed in the OnDrop method to determine whether the data can be converted to a Brush.

    • If the data is converted to a valid Brush, applies it to the Fill of the Ellipse.

  4. Add the following OnDragLeave override to provide class handling for the DragLeave event.

    protected override void OnDragLeave(DragEventArgs e)
    {
        base.OnDragLeave(e);
        // Undo the preview that was applied in OnDragEnter.
        circleUI.Fill = _previousFill;
    }
    
    Protected Overrides Sub OnDragLeave(ByVal e As System.Windows.DragEventArgs)
        MyBase.OnDragLeave(e)
        ' Undo the preview that was applied in OnDragEnter.
        circleUI.Fill = _previousFill
    End Sub
    

    This OnDragLeave override performs the following tasks:

    • Applies the Brush saved in the _previousFill variable to the Fill of the Ellipse that provides the UI of the Circle user control.
  5. Press F5 to build and run the application.

  6. Select the text green in the TextBox.

  7. Drag the text over a Circle control without dropping it. The Circle changes from blue to green.

    Preview the effects of a drag-and-drop operation

  8. Drag the text away from the Circle control. The Circle changes from green back to blue.

Enable a Panel to Receive Dropped Data

In this section, you enable the panels that host the Circle user controls to act as drop targets for dragged Circle data. You will implement code that enables you to move a Circle from one panel to another, or to make a copy of a Circle control by holding down the Ctrl key while dragging and dropping a Circle.

  1. Open MainWindow.xaml.

  2. As shown in the following XAML, in each of the StackPanel controls, add handlers for the DragOver and Drop events. Name the DragOver event handler, panel_DragOver, and name the Drop event handler, panel_Drop.

    By default, the panels aren't drop targets. To enable them, add the AllowDrop property to both panels and set the value to true.

    <StackPanel Grid.Column="0"
                Background="Beige"
                AllowDrop="True"
                DragOver="panel_DragOver"
                Drop="panel_Drop">
        <TextBox Width="Auto" Margin="2"
                 Text="green"/>
        <local:Circle Margin="2" />
        <local:Circle Margin="2" />
    </StackPanel>
    <StackPanel Grid.Column="1"
                Background="Bisque"
                AllowDrop="True"
                DragOver="panel_DragOver"
                Drop="panel_Drop">
    </StackPanel>
    
  3. Open MainWindows.xaml.cs or MainWindow.xaml.vb.

  4. Add the following code for the DragOver event handler.

    private void panel_DragOver(object sender, DragEventArgs e)
    {
        if (e.Data.GetDataPresent("Object"))
        {
            // These Effects values are used in the drag source's
            // GiveFeedback event handler to determine which cursor to display.
            if (e.KeyStates == DragDropKeyStates.ControlKey)
            {
                e.Effects = DragDropEffects.Copy;
            }
            else
            {
                e.Effects = DragDropEffects.Move;
            }
        }
    }
    
    Private Sub panel_DragOver(ByVal sender As System.Object, ByVal e As System.Windows.DragEventArgs)
        If e.Data.GetDataPresent("Object") Then
            ' These Effects values are used in the drag source's
            ' GiveFeedback event handler to determine which cursor to display.
            If e.KeyStates = DragDropKeyStates.ControlKey Then
                e.Effects = DragDropEffects.Copy
            Else
                e.Effects = DragDropEffects.Move
            End If
        End If
    End Sub
    

    This DragOver event handler performs the following tasks:

    • Checks that the dragged data contains the "Object" data that was packaged in the DataObject by the Circle user control and passed in the call to DoDragDrop.

    • If the "Object" data is present, checks whether the Ctrl key is pressed.

    • If the Ctrl key is pressed, sets the Effects property to Copy. Otherwise, set the Effects property to Move.

  5. Add the following code for the Drop event handler.

    private void panel_Drop(object sender, DragEventArgs e)
    {
        // If an element in the panel has already handled the drop,
        // the panel should not also handle it.
        if (e.Handled == false)
        {
            Panel _panel = (Panel)sender;
            UIElement _element = (UIElement)e.Data.GetData("Object");
    
            if (_panel != null && _element != null)
            {
                // Get the panel that the element currently belongs to,
                // then remove it from that panel and add it the Children of
                // the panel that its been dropped on.
                Panel _parent = (Panel)VisualTreeHelper.GetParent(_element);
    
                if (_parent != null)
                {
                    if (e.KeyStates == DragDropKeyStates.ControlKey &&
                        e.AllowedEffects.HasFlag(DragDropEffects.Copy))
                    {
                        Circle _circle = new Circle((Circle)_element);
                        _panel.Children.Add(_circle);
                        // set the value to return to the DoDragDrop call
                        e.Effects = DragDropEffects.Copy;
                    }
                    else if (e.AllowedEffects.HasFlag(DragDropEffects.Move))
                    {
                        _parent.Children.Remove(_element);
                        _panel.Children.Add(_element);
                        // set the value to return to the DoDragDrop call
                        e.Effects = DragDropEffects.Move;
                    }
                }
            }
        }
    }
    
    Private Sub panel_Drop(ByVal sender As System.Object, ByVal e As System.Windows.DragEventArgs)
        ' If an element in the panel has already handled the drop,
        ' the panel should not also handle it.
        If e.Handled = False Then
            Dim _panel As Panel = sender
            Dim _element As UIElement = e.Data.GetData("Object")
    
            If _panel IsNot Nothing And _element IsNot Nothing Then
                ' Get the panel that the element currently belongs to,
                ' then remove it from that panel and add it the Children of
                ' the panel that its been dropped on.
    
                Dim _parent As Panel = VisualTreeHelper.GetParent(_element)
                If _parent IsNot Nothing Then
                    If e.KeyStates = DragDropKeyStates.ControlKey And _
                        e.AllowedEffects.HasFlag(DragDropEffects.Copy) Then
                        Dim _circle As New Circle(_element)
                        _panel.Children.Add(_circle)
                        ' set the value to return to the DoDragDrop call
                        e.Effects = DragDropEffects.Copy
                    ElseIf e.AllowedEffects.HasFlag(DragDropEffects.Move) Then
                        _parent.Children.Remove(_element)
                        _panel.Children.Add(_element)
                        ' set the value to return to the DoDragDrop call
                        e.Effects = DragDropEffects.Move
                    End If
                End If
            End If
        End If
    End Sub
    

    This Drop event handler performs the following tasks:

    • Checks whether the Drop event has already been handled. For instance, if a Circle is dropped on another Circle which handles the Drop event, you do not want the panel that contains the Circle to also handle it.

    • If the Drop event is not handled, checks whether the Ctrl key is pressed.

    • If the Ctrl key is pressed when the Drop happens, makes a copy of the Circle control and add it to the Children collection of the StackPanel.

    • If the Ctrl key is not pressed, moves the Circle from the Children collection of its parent panel to the Children collection of the panel that it was dropped on.

    • Sets the Effects property to notify the DoDragDrop method whether a move or copy operation was performed.

  6. Press F5 to build and run the application.

  7. Select the text green from the TextBox.

  8. Drag the text over a Circle control and drop it.

  9. Drag a Circle control from the left panel to the right panel and drop it. The Circle is removed from the Children collection of the left panel and added to the Children collection of the right panel.

  10. Drag a Circle control from the panel it is in to the other panel and drop it while pressing the Ctrl key. The Circle is copied and the copy is added to the Children collection of the receiving panel.

    Dragging a Circle while pressing the CTRL key

See also