Compartir a través de


Guía paso a paso: Habilitar arrastrar y soltar en un control de usuario

En este tutorial se muestra cómo crear un control de usuario personalizado que pueda participar en la transferencia de datos de arrastrar y colocar en Windows Presentation Foundation (WPF).

En este tutorial, creará un WPF UserControl personalizado que representa una forma de círculo. Implementará la funcionalidad en el control para habilitar la transferencia de datos mediante arrastrar y soltar. Por ejemplo, si arrastra desde un control Circle a otro, el color de relleno se copia desde el círculo de origen al círculo de destino. Si arrastra desde un control Circle a TextBox, la representación de cadena del color Fill se copia en TextBox. También creará una aplicación pequeña que contiene dos controles de panel y un TextBox para probar la funcionalidad de arrastrar y soltar. Escribirá código que permita a los paneles procesar los datos de círculo eliminados, lo que le permitirá mover o copiar círculos de la colección Children de un panel al otro.

En este tutorial se ilustran las siguientes tareas:

  • Cree un control de usuario personalizado.

  • Habilite el control de usuario para que sea un origen de arrastre.

  • Habilite el control de usuario para que sea un objetivo de soltar.

  • Habilite un panel para recibir los datos eliminados del control de usuario.

Prerrequisitos

Necesita Visual Studio para completar este tutorial.

Creación del proyecto de aplicación

En esta sección, creará la infraestructura de la aplicación, que incluye una página principal con dos paneles y un TextBox.

  1. Cree un nuevo proyecto de aplicación de WPF en Visual Basic o Visual C# denominado DragDropExample. Para obtener más información, vea Tutorial: Mi primera aplicación de escritorio de WPF.

  2. Abra MainWindow.xaml.

  3. Agregue el marcado siguiente entre las etiquetas de apertura y cierre Grid .

    Este marcado crea la interfaz de usuario para la aplicación de prueba.

    <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>
    

Agregar un nuevo control de usuario al proyecto

En esta sección, agregará un nuevo control de usuario al proyecto.

  1. En el menú Proyecto, seleccione Agregar control de usuario.

  2. En el cuadro de diálogo Agregar nuevo elemento , cambie el nombre a Circle.xamly haga clic en Agregar.

    Circle.xaml y su código subyacente se agregan al proyecto.

  3. Abre Circle.xaml.

    Este archivo contendrá los elementos de la interfaz de usuario del control de usuario.

  4. Agregue el siguiente marcado a la raíz Grid para crear un control de usuario simple que tenga un círculo azul como su interfaz de usuario.

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

  6. En C#, agregue el código siguiente después del constructor sin parámetros para crear un constructor de copia. En Visual Basic, agregue el código siguiente para crear un constructor sin parámetros y un constructor de copia.

    Para permitir que el control de usuario se copie, agregue un método de constructor de copia en el archivo de código subyacente. En el control de usuario simplificado Circle, solo copiarás el relleno y el tamaño del control Circle.

    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
    

Adición del control de usuario a la ventana principal

  1. Abra MainWindow.xaml.

  2. Agregue el código XAML siguiente a la etiqueta de apertura Window para crear una referencia de espacio de nombres XML a la aplicación actual.

    xmlns:local="clr-namespace:DragDropExample"
    
  3. En el primer StackPanel, agregue el siguiente CÓDIGO XAML para crear dos instancias del control de usuario Circle en el primer panel.

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

    El CÓDIGO XAML completo del panel tiene el siguiente aspecto.

    <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>
    

Implementación de eventos de arrastrar código fuente en el control de usuario

En esta sección, sobrescribirá el método OnMouseMove e iniciará la operación de arrastrar y soltar.

Si se inicia un arrastre (se presiona un botón del ratón y se mueve el ratón), empaquetas los datos que se transferirán en un componente DataObject. En este caso, el control Circle empaquetará tres elementos de datos; una representación de cadena de su color relleno, una representación doble de su alto y una copia de sí misma.

Para iniciar una operación de arrastrar y colocar

  1. Abra Circle.xaml.cs o Circle.xaml.vb.

  2. Agregue la siguiente OnMouseMove sobrecarga para proporcionar el manejo de clases para el evento MouseMove.

    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
    

    Esta OnMouseMove sobrescripción realiza las siguientes tareas:

    • Comprueba si se presiona el botón izquierdo del mouse mientras se mueve el mouse.

    • Empaqueta los datos del círculo en un DataObject. En este caso, el control Círculo empaqueta tres elementos de datos: una representación en cadena de su color de relleno, una representación doble de su altura y una copia de sí mismo.

    • Llama al método estático DragDrop.DoDragDrop para iniciar la operación de arrastrar y colocar. Pase los tres parámetros siguientes al DoDragDrop método :

      • dragSource – Referencia a este control.

      • data – El DataObject creado en el código anterior.

      • allowedEffects : las operaciones de arrastrar y colocar permitidas, que son Copy o Move.

  3. Presione F5 para compilar y ejecutar la aplicación.

  4. Haga clic en uno de los controles de Círculo y arrástrelo sobre los paneles, el otro círculo y el TextBox. Al arrastrar TextBox, el cursor cambia para indicar que se está moviendo.

  5. Al arrastrar un círculo sobre el TextBox, presione la tecla Ctrl. Observe cómo cambia el cursor para indicar una copia.

  6. Arrastre y coloque un círculo sobre el TextBox. La representación en cadena del color de relleno del círculo se anexa a TextBox.

    Representación de cadena del color de relleno del círculo

De forma predeterminada, el cursor cambiará durante una operación de arrastrar y colocar para indicar qué efecto tendrá la colocación de los datos. Puede personalizar los comentarios proporcionados al usuario controlando el GiveFeedback evento y estableciendo un cursor diferente.

Enviar comentarios al usuario

  1. Abra Circle.xaml.cs o Circle.xaml.vb.

  2. Agregue la siguiente OnGiveFeedback sobrecarga para proporcionar el manejo de clases para el evento GiveFeedback.

    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
    

    Esta OnGiveFeedback sobrescripción realiza las siguientes tareas:

    • Comprueba los valores Effects establecidos en el controlador de eventos del objetivo de DragOver colocación.

    • Establece un cursor personalizado basado en el Effects valor . El cursor está pensado para proporcionar comentarios visuales al usuario sobre qué efecto tendrá la eliminación de los datos.

  3. Presione F5 para compilar y ejecutar la aplicación.

  4. Arrastre uno de los controles de Círculo sobre los paneles, el otro círculo y el TextBox. Tenga en cuenta que los cursores ahora son los cursores personalizados que especificó en la OnGiveFeedback sobrescritura.

    Arrastrar y colocar con cursores personalizados

  5. Seleccione el texto green del TextBox.

  6. Arrastre el green texto a un control de Círculo. Observe que los cursores predeterminados se muestran para indicar los efectos de la operación de arrastrar y colocar. El cursor de comentarios siempre se establece mediante el origen de arrastre.

Implementar eventos de destino de arrastre en el control de usuario

En esta sección, especificará que el control de usuario es un destino de arrastre, sobrescribirá los métodos que permiten que el control de usuario sea un destino de arrastre y procesará los datos que se dejan caer en él.

Para permitir que el control de usuario sea un destino de soltar

  1. Abre Circle.xaml.

  2. En la etiqueta de apertura UserControl, agregue AllowDrop propiedad y establézcala en 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">
    

Se OnDrop llama al método cuando la AllowDrop propiedad se establece en true y los datos del origen de arrastre se quitan en el control de usuario Circle. En este método, procesará los datos eliminados y los aplicará al Círculo.

Para procesar los datos descartados

  1. Abra Circle.xaml.cs o Circle.xaml.vb.

  2. Agregue la siguiente OnDrop sobrecarga para proporcionar el manejo de clases para el evento Drop.

    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
    

    Esta OnDrop sobrescripción realiza las siguientes tareas:

    • Usa el GetDataPresent método para comprobar si los datos arrastrados contienen un objeto de cadena.

    • Usa el GetData método para extraer los datos de cadena si está presente.

    • Utiliza un BrushConverter para intentar convertir la cadena en un Brush.

    • Si la conversión se realiza correctamente, aplica el pincel al Fill del Ellipse que proporciona la interfaz de usuario del control Circle.

    • Marca el Drop evento como controlado. Debe marcar el evento drop como controlado para que otros elementos que reciban este evento sepan que el control de usuario Circle lo controló.

  3. Presione F5 para compilar y ejecutar la aplicación.

  4. Seleccione el texto green en el TextBox.

  5. Arrastre el texto a un control de tipo círculo y colóquelo. El círculo cambia de azul a verde.

    Convertir una cadena en un pincel

  6. Escriba el texto green en el TextBox.

  7. Seleccione el texto gre en el TextBox.

  8. Arrástrelo a un control Circle y colóquelo. Observe que el cursor cambia para indicar que se permite soltar, pero el color del círculo no cambia porque gre no es un color válido.

  9. Arrastre desde el control círculo verde y colóquelo en el control círculo azul. El círculo cambia de azul a verde. Observe que el cursor que se muestra depende de si el TextBox o el círculo son el origen de arrastre.

Establecer la AllowDrop propiedad en true y procesar los datos eliminados es todo lo que es necesario para permitir que un elemento sea un destino de colocación. Sin embargo, para proporcionar una mejor experiencia de usuario, también debe controlar los eventos DragEnter, DragLeave y DragOver. En estos eventos, puede realizar comprobaciones y proporcionar comentarios adicionales al usuario antes de eliminar los datos.

Cuando los datos son arrastrados sobre el control de usuario Circle, el control debe notificar al origen del arrastre si puede procesar los datos que están siendo arrastrados. Si el control no sabe cómo procesar los datos, debe rechazar la eliminación. Para ello, controlará el evento DragOver y establecerá la propiedad Effects.

Para comprobar que se permite la eliminación de datos

  1. Abra Circle.xaml.cs o Circle.xaml.vb.

  2. Agregue la siguiente OnDragOver sobrecarga para proporcionar el manejo de clases para el evento DragOver.

    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
    

    Esta OnDragOver sobrescripción realiza las siguientes tareas:

    • Establece la propiedad Effects en None.

    • Realiza las mismas comprobaciones que se realizan en el método OnDrop para determinar si el control de usuario Circle puede procesar los datos arrastrados.

    • Si el control de usuario puede procesar los datos, establece la Effects propiedad en Copy o Move.

  3. Presione F5 para compilar y ejecutar la aplicación.

  4. Seleccione el texto gre en el TextBox.

  5. Arrastre el texto a un control Círculo. Nótese que el cursor ahora cambia para indicar que la acción de soltar no está permitida porque gre no es un color válido.

Puede mejorar aún más la experiencia del usuario aplicando una vista previa de la operación de colocación. Para el control de usuario Circle, invalidará los métodos OnDragEnter y OnDragLeave. Cuando los datos se arrastran sobre el control, el fondo Fill actual se guarda en una variable de marcador de posición. A continuación, la cadena se convierte en un pincel y se aplica al Ellipse, que proporciona la interfaz de usuario del círculo. Si los datos se arrastran fuera del círculo sin quitarse, el valor original Fill se vuelve a aplicar al círculo.

Para obtener una vista previa de los efectos de la operación de arrastrar y colocar

  1. Abra Circle.xaml.cs o Circle.xaml.vb.

  2. En la clase Circle, declare una variable privada Brush denominada _previousFill e inicialícela en null.

    public partial class Circle : UserControl
    {
        private Brush _previousFill = null;
    
    Public Class Circle
        Private _previousFill As Brush = Nothing
    
  3. Agregue la siguiente OnDragEnter sobrecarga para proporcionar el manejo de clases para el evento DragEnter.

    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
    

    Esta OnDragEnter sobrescripción realiza las siguientes tareas:

    • Guarda la propiedad Fill del Ellipse en la variable _previousFill.

    • Realiza las mismas comprobaciones que se realizan en el OnDrop método para determinar si los datos se pueden convertir en .Brush

    • Si los datos se convierten en un Brush válido, los aplica a Fill de el sistema Ellipse.

  4. Agregue la siguiente OnDragLeave sobrecarga para proporcionar el manejo de clases para el evento DragLeave.

    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
    

    Esta OnDragLeave sobrescripción realiza las siguientes tareas:

    • Aplica el Brush guardado en la variable _previousFill al Fill del Ellipse que proporciona la interfaz de usuario del control de usuario Circle.
  5. Presione F5 para compilar y ejecutar la aplicación.

  6. Seleccione el texto green en el TextBox.

  7. Arrastre el texto sobre un control circular sin soltarlo. El círculo cambia de azul a verde.

    Obtener una vista previa de los efectos de una operación de arrastrar y colocar

  8. Arrastre el texto fuera del alcance del control 'Circle'. El círculo cambia de verde a azul.

Habilitar un panel para recibir datos arrastrados

En esta sección, habilitará los paneles que hospedan los controles de usuario Circle para que actúen como destinos de colocación para los datos de Circle arrastrados. Implementará código que le permitirá mover un Círculo de un panel a otro, o realizar una copia de un control Círculo manteniendo presionada la tecla Ctrl mientras arrastra y suelta un Círculo.

  1. Abra MainWindow.xaml.

  2. Como se muestra en el siguiente XAML, en cada uno de los controles StackPanel, agrega controladores para los eventos DragOver y Drop. Asigne el nombre al controlador de eventos DragOver, panel_DragOver, y asigne el nombre al controlador de eventos Drop, panel_Drop.

    De forma predeterminada, los paneles no son destinos de eliminación. Para habilitarlos, agregue la AllowDrop propiedad a ambos paneles y establezca el valor en 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. Abra MainWindows.xaml.cs o MainWindow.xaml.vb.

  4. Agregue el código siguiente para el controlador de DragOver eventos.

    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
    

    Este DragOver controlador de eventos realiza las siguientes tareas:

    • Comprueba que los datos arrastrados contienen los datos "Object" empaquetados en el DataObject control de usuario Circle y pasados en la llamada a DoDragDrop.

    • Si los datos "Object" están presentes, comprueba si se presiona la tecla Ctrl .

    • Si se presiona la tecla Ctrl, establece la propiedad Effects en Copy. De lo contrario, establezca la propiedad Effects en Move.

  5. Agregue el código siguiente para el controlador de Drop eventos.

    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
    

    Este Drop controlador de eventos realiza las siguientes tareas:

    • Comprueba si el Drop evento ya se ha controlado. Por ejemplo, si se suelta un círculo sobre otro círculo que maneja el Drop evento, no desea que el panel que contiene el círculo también lo maneje.

    • Si el evento Drop no se maneja, comprueba si se presiona la tecla Ctrl

    • Si se presiona la tecla Ctrl en el momento en que Drop ocurre, realiza una copia del control Circle y la agrega a la colección Children de StackPanel.

    • Si no se presiona la tecla Ctrl, mueve el círculo de la colección del panel padre a la colección del panel en el que se soltó.

    • Establece la Effects propiedad para notificar al DoDragDrop método si se realizó una operación de movimiento o copia.

  6. Presione F5 para compilar y ejecutar la aplicación.

  7. Seleccione el texto green del TextBox.

  8. Arrastre el texto sobre un control círculo y suéltelo.

  9. Arrastre un control de círculo desde el panel izquierdo hasta el panel derecho y suéltelo. El círculo se quita de la Children colección del panel izquierdo y se agrega a la colección Niños del panel derecho.

  10. Arrastre un control Circle desde el panel donde se encuentra hasta el otro panel y suéltelo mientras presiona la tecla Ctrl. El círculo se copia y la copia se agrega a la Children colección del panel receptor.

    Arrastrar un círculo mientras presiona la tecla CTRL

Consulte también