Partager via


Guide étape par étape : activation du glisser-déposer sur un contrôle utilisateur

Cette procédure pas à pas montre comment créer un contrôle utilisateur personnalisé qui peut participer au transfert de données glisser-déplacer dans Windows Presentation Foundation (WPF).

Dans cette procédure pas à pas, vous allez créer un UserControl WPF personnalisé qui représente une forme de cercle. Vous allez implémenter des fonctionnalités sur le contrôle pour activer le transfert de données par glisser-déplacer. Par exemple, si vous faites glisser d’un contrôle Circle vers un autre, les données de couleur de remplissage sont copiées du cercle source vers la cible. Si vous faites glisser d'un contrôle de type Cercle vers l'élément TextBox, la chaîne représentant la couleur de remplissage est copiée dans le TextBox. Vous allez également créer une petite application qui contient deux contrôles de panneau et une TextBox pour tester la fonctionnalité glisser-déplacer. Vous allez écrire du code qui permet aux panneaux de traiter les données de Circle déposées, ce qui vous permettra de déplacer ou de copier des Circles de la collection Enfants d’un panneau vers l’autre.

Cette procédure pas à pas illustre les tâches suivantes :

  • Créez un contrôle utilisateur personnalisé.

  • Permettre au contrôle utilisateur d’être une source de glissement.

  • Permettre au contrôle utilisateur d’être une cible de suppression.

  • Activez un panneau pour recevoir les données supprimées du contrôle utilisateur.

Conditions préalables

Vous avez besoin de Visual Studio pour effectuer cette procédure pas à pas.

Créer le projet d’application

Dans cette section, vous allez créer l’infrastructure d’application, qui inclut une page principale avec deux panneaux et un TextBox.

  1. Créez un projet d’application WPF dans Visual Basic ou Visual C# nommé DragDropExample. Pour plus d’informations, consultez procédure pas à pas : Ma première application de bureau WPF.

  2. Ouvrez MainWindow.xaml.

  3. Ajoutez le balisage suivant entre les balises d’ouverture et de fermeture Grid.

    Ce balisage crée l’interface utilisateur de l’application de test.

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

Ajouter un nouveau contrôle utilisateur au projet

Dans cette section, vous allez ajouter un nouveau contrôle utilisateur au projet.

  1. Dans le menu Projet, sélectionnez Ajouter un contrôle utilisateur.

  2. Dans la boîte de dialogue Ajouter un nouvel élément, remplacez le nom par Circle.xaml, puis cliquez sur Ajouter.

    Circle.xaml et son code-behind associé sont ajoutés au projet.

  3. Ouvrez Circle.xaml.

    Ce fichier contient les éléments d’interface utilisateur du contrôle utilisateur.

  4. Ajoutez le balisage suivant à la racine Grid pour créer un contrôle utilisateur simple qui a un cercle bleu comme interface utilisateur.

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

  6. En C#, ajoutez le code suivant après le constructeur sans paramètre pour créer un constructeur de copie. Dans Visual Basic, ajoutez le code suivant pour créer à la fois un constructeur sans paramètre et un constructeur de copie.

    Pour permettre au contrôle utilisateur d’être copié, vous ajoutez une méthode de constructeur de copie dans le fichier code-behind. Dans le contrôle utilisateur Circle simplifié, vous ne copierez que le remplissage et la taille du contrôle utilisateur.

    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
    

Ajouter le contrôle utilisateur à la fenêtre principale

  1. Ouvrez MainWindow.xaml.

  2. Ajoutez le code XAML suivant à la balise Window ouvrante pour créer une référence d’espace de noms XML à l’application actuelle.

    xmlns:local="clr-namespace:DragDropExample"
    
  3. Dans la première StackPanel, ajoutez le code XAML suivant pour créer deux instances du contrôle utilisateur Circle dans le premier panneau.

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

    Le code XAML complet pour le panneau ressemble à ce qui suit.

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

Implémenter les événements de la source glisser dans le contrôle utilisateur

Dans cette section, vous allez remplacer la méthode OnMouseMove et lancer l’opération glisser-déplacer.

Si un glisser-déposer est démarré (un bouton de la souris est enfoncé et que la souris est déplacée), vous allez encapsuler les données à transférer dans un DataObject. Dans ce cas, le contrôle Circle empaquetera trois éléments de données ; une représentation sous forme de chaîne de sa couleur de remplissage, une représentation double de sa hauteur et une copie de lui-même.

Pour lancer une opération de glisser-déplacer

  1. Ouvrez Circle.xaml.cs ou Circle.xaml.vb.

  2. Ajoutez le remplacement OnMouseMove suivant pour fournir la gestion des classes pour l’événement 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
    

    Ce remplacement OnMouseMove effectue les tâches suivantes :

    • Vérifie si le bouton gauche de la souris est enfoncé pendant le déplacement de la souris.

    • Empaquette les données Circle dans un DataObject. Dans ce cas, le contrôle Circle empaquette trois éléments de données ; une représentation sous forme de chaîne de sa couleur de remplissage, une représentation double de sa hauteur et une copie de lui-même.

    • Appelle la méthode statique DragDrop.DoDragDrop pour initier l'opération de Glisser-Déplacer. Vous transmettez les trois paramètres suivants à la méthode DoDragDrop :

      • dragSource : référence à ce contrôle.

      • data : DataObject créé dans le code précédent.

      • allowedEffects : opérations de glisser-déplacer autorisées, qui sont Copy ou Move.

  3. Appuyez sur F5 pour générer et exécuter l’application.

  4. Cliquez sur l’un des contrôles Circle et faites-le glisser sur les panneaux, l’autre cercle et le TextBox. Lorsque vous faites glisser le curseur sur le TextBox, le curseur change pour indiquer un déplacement.

  5. Lorsque vous faites glisser un cercle sur le TextBox, appuyez sur la touche Ctrl. Notez comment le curseur change pour indiquer une copie.

  6. Faites glisser et déposez un cercle sur le TextBox. La représentation sous forme de chaîne de la couleur de remplissage du cercle est ajoutée au TextBox.

    représentation sous forme de chaîne de la couleur de remplissage du cercle

Par défaut, le curseur change pendant une opération de glisser-déplacer pour indiquer l’effet de suppression des données. Vous pouvez personnaliser les commentaires donnés à l’utilisateur en gérant l’événement GiveFeedback et en définissant un autre curseur.

Envoyer des commentaires à l’utilisateur

  1. Ouvrez Circle.xaml.cs ou Circle.xaml.vb.

  2. Ajoutez le remplacement OnGiveFeedback suivant pour fournir la gestion des classes pour l’événement 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
    

    Cette substitution OnGiveFeedback effectue les tâches suivantes :

    • Vérifie les valeurs Effects définies dans le gestionnaire d’événements DragOver de la cible de suppression.

    • Définit un curseur personnalisé en fonction de la valeur Effects. Le curseur est destiné à donner des commentaires visuels à l’utilisateur sur l’effet de suppression des données.

  3. Appuyez sur F5 pour générer et exécuter l’application.

  4. Faites glisser l’un des contrôles Circle sur les panneaux, l’autre cercle et le TextBox. Notez que les curseurs sont désormais les curseurs personnalisés que vous avez spécifiés dans la surdéfinition OnGiveFeedback.

    glisser-déplacer avec des curseurs personnalisés

  5. Sélectionnez le texte green dans le TextBox.

  6. Faites glisser le texte green vers un contrôle Circle. Notez que les curseurs par défaut sont affichés pour indiquer les effets de l’opération de glisser-déplacer. Le curseur de retour est toujours défini par la source de glissement.

Implémenter des événements drop target dans le contrôle utilisateur

Dans cette section, vous allez spécifier que le contrôle utilisateur est une cible de suppression, remplacer les méthodes qui permettent au contrôle utilisateur d’être une cible de suppression et de traiter les données qui y sont supprimées.

Pour permettre au contrôle utilisateur d’être une cible de suppression

  1. Ouvrez Circle.xaml.

  2. Dans la balise UserControl ouvrante, ajoutez la propriété AllowDrop et définissez-la sur 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">
    

La méthode OnDrop est appelée lorsque la propriété AllowDrop est définie sur true et que les données de la source de glisser-déposer sont déposées sur le contrôle utilisateur Circle. Dans cette méthode, vous allez traiter les données qui ont été supprimées et appliquer les données au cercle.

Pour traiter les données déposées

  1. Ouvrez Circle.xaml.cs ou Circle.xaml.vb.

  2. Ajoutez le remplacement OnDrop suivant pour fournir la gestion de classe pour l’événement 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
    

    Ce remplacement OnDrop effectue les tâches suivantes :

    • Utilise la méthode GetDataPresent pour vérifier si les données déplacées contiennent un objet de chaîne.

    • Utilise la méthode GetData pour extraire les données de chaîne si elles sont présentes.

    • Utilise un BrushConverter pour essayer de convertir la chaîne en Brush.

    • Si la conversion réussit, applique le pinceau à la Fill du Ellipse qui fournit l'interface utilisateur du contrôle Cercle.

    • Marque l’événement Drop comme géré. Vous devez marquer l’événement de suppression comme géré afin que d’autres éléments qui reçoivent cet événement sachent que le contrôle utilisateur Circle l’a géré.

  3. Appuyez sur F5 pour générer et exécuter l’application.

  4. Sélectionnez le texte green dans le TextBox.

  5. Faites glisser le texte vers un contrôle circulaire et relâchez-le. Le cercle passe du bleu au vert.

    Convertir une chaîne de caractères en pinceau

  6. Tapez le texte green dans le TextBox.

  7. Sélectionnez le texte gre dans le TextBox.

  8. Faites-le glisser vers un contrôle de type "Circle" et relâchez-le. Notez que le curseur change pour indiquer que la suppression est autorisée, mais que la couleur du cercle ne change pas, car gre n’est pas une couleur valide.

  9. Faites glisser à partir du contrôle Cercle vert et déposez-le sur le contrôle Cercle bleu. Le cercle passe du bleu au vert. Notez que le curseur affiché dépend de la source de déplacement, qu'il s'agisse du TextBox ou du cercle.

La définition de la propriété AllowDrop sur true et le traitement des données supprimées est tout ce qui est nécessaire pour permettre à un élément d’être une cible de suppression. Toutefois, pour offrir une meilleure expérience utilisateur, vous devez également gérer les événements DragEnter, DragLeaveet DragOver. Dans ces événements, vous pouvez effectuer des vérifications et fournir des commentaires supplémentaires à l’utilisateur avant la suppression des données.

Lorsque les données sont glissées sur le contrôle utilisateur Circle, celui-ci doit avertir la source du glissement s'il peut traiter les données qui sont glissées. Si le contrôle ne sait pas comment traiter les données, il doit refuser la suppression. Pour ce faire, vous allez gérer l’événement DragOver et définir la propriété Effects.

Pour vérifier que la suppression des données est autorisée

  1. Ouvrez Circle.xaml.cs ou Circle.xaml.vb.

  2. Ajoutez le remplacement OnDragOver suivant pour fournir la gestion des classes pour l’événement 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
    

    Cette surcharge OnDragOver effectue les tâches suivantes :

    • Définit la propriété Effects sur None.

    • Effectue les mêmes vérifications que celles effectuées dans la méthode OnDrop pour déterminer si le contrôle utilisateur Circle peut traiter les données déplacées.

    • Si le contrôle utilisateur est capable de traiter les données, il définit la propriété Effects sur Copy ou Move.

  3. Appuyez sur F5 pour générer et exécuter l’application.

  4. Sélectionnez le texte gre dans le TextBox.

  5. Faites glisser le texte vers un contrôle de cercle. Notez que le curseur change maintenant pour indiquer que la suppression n’est pas autorisée, car gre n’est pas une couleur valide.

Vous pouvez améliorer davantage l’expérience utilisateur en appliquant un aperçu de l’opération de suppression. Pour le contrôle utilisateur Circle, vous remplacerez les méthodes OnDragEnter et OnDragLeave. Lorsque les données sont déplacées sur le contrôle, l’arrière-plan actuel Fill est sauvegardé dans une variable temporaire. La chaîne est ensuite convertie en pinceau et appliquée à Ellipse, qui fournit l'interface utilisateur de Circle. Si les données sont déplacées hors du cercle sans être supprimées, la valeur de Fill d’origine est réapproguée au cercle.

Pour afficher un aperçu des effets de l’opération de glisser-déplacer

  1. Ouvrez Circle.xaml.cs ou Circle.xaml.vb.

  2. Dans la classe Circle, déclarez une variable de Brush privée nommée _previousFill et initialisez-la sur null.

    public partial class Circle : UserControl
    {
        private Brush _previousFill = null;
    
    Public Class Circle
        Private _previousFill As Brush = Nothing
    
  3. Ajoutez le remplacement OnDragEnter suivant pour fournir la gestion des classes pour l’événement 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
    

    Cette surcharge OnDragEnter effectue les tâches suivantes :

    • Enregistre la propriété Fill du Ellipse dans la variable _previousFill.

    • Effectue les mêmes vérifications que celles effectuées dans la méthode OnDrop pour déterminer si les données peuvent être converties en Brush.

    • Lorsque les données sont converties en un Brushvalide, elles sont appliquées à l'Fill du Ellipse.

  4. Ajoutez le remplacement OnDragLeave suivant pour fournir la gestion de classe pour l’événement 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
    

    Cette surcharge OnDragLeave effectue les tâches suivantes :

    • Applique la Brush enregistrée dans la variable _previousFill à la Fill du Ellipse qui fournit l’interface utilisateur du contrôle utilisateur Circle.
  5. Appuyez sur F5 pour générer et exécuter l’application.

  6. Sélectionnez le texte green dans le TextBox.

  7. Faites glisser le texte sur un contrôle Cercle sans le supprimer. Le cercle passe du bleu au vert.

    Afficher un aperçu des effets d’une opération de glisser-déplacer

  8. Faites glisser le texte vers l’extérieur du contrôle Circle. Le cercle passe du vert au bleu.

Activer un panneau pour recevoir des données déposées

Dans cette section, vous allez activer les panneaux qui accueillent les contrôles utilisateur Circle pour qu'ils puissent servir de cibles de dépôt pour les données Circle déplacées. Vous allez implémenter du code qui vous permet de déplacer un cercle d’un panneau vers un autre ou d’effectuer une copie d’un contrôle Circle en maintenant enfoncée la touche Ctrl tout en faisant glisser-déplacer un cercle.

  1. Ouvrez MainWindow.xaml.

  2. Comme indiqué dans le code XAML suivant, dans chacun des contrôles StackPanel, ajoutez des gestionnaires pour les événements DragOver et Drop. Nommez le gestionnaire d’événements DragOver, panel_DragOveret nommez le gestionnaire d’événements Drop, panel_Drop.

    Par défaut, les panneaux ne sont pas des cibles de suppression. Pour les activer, ajoutez la propriété AllowDrop aux deux panneaux et définissez la valeur sur 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. Ouvrez MainWindows.xaml.cs ou MainWindow.xaml.vb.

  4. Ajoutez le code suivant pour le gestionnaire d’événements DragOver.

    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
    

    Ce gestionnaire d’événements DragOver effectue les tâches suivantes :

    • Vérifie que les données déplacées contiennent les données « Object » qui ont été emballées dans le DataObject par le contrôle utilisateur Circle et transmises lors de l’appel à DoDragDrop.

    • Si les données « Object » sont présentes, vérifie si la touche Ctrl est enfoncée.

    • Si la touche Ctrl est enfoncée, définit la propriété Effects sur Copy. Sinon, définissez la propriété Effects sur Move.

  5. Ajoutez le code suivant pour le gestionnaire d’événements Drop.

    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
    

    Ce gestionnaire d’événements Drop effectue les tâches suivantes :

    • Vérifie si l’événement Drop a déjà été géré. Par exemple, si un Cercle est déposé sur un autre Cercle qui gère l’événement Drop, vous ne souhaitez pas que le Panneau contenant le Cercle gère également cet événement.

    • Si l’événement Drop n’est pas géré, vérifie si la touche Ctrl est enfoncée.

    • Si la touche Ctrl est enfoncée lorsque le Drop se produit, effectue une copie du contrôle Circle et l’ajoute à la collection Children du StackPanel.

    • Si la touche Ctrl n’est pas enfoncée, déplace le cercle de la collection Children de son panneau parent vers la collection Children du panneau sur lequel il a été déposé.

    • Définit la propriété Effects pour notifier la méthode DoDragDrop si une opération de déplacement ou de copie a été effectuée.

  6. Appuyez sur F5 pour générer et exécuter l’application.

  7. Sélectionnez le texte green dans le TextBox.

  8. Faites glisser le texte sur un contrôle Circle et déposez-le.

  9. Faites glisser un contrôle Cercle du panneau gauche vers le panneau droit et déposez-le. Le cercle est supprimé de la collection Children du volet gauche et ajouté à la collection Children du panneau droit.

  10. Faites glisser un contrôle Cercle depuis le panneau où il se trouve vers l'autre panneau et déposez-le tout en appuyant sur la touche Ctrl . Le cercle est copié et la copie est ajoutée à la collection Children du panneau de réception.

    faire glisser un cercle tout en appuyant sur la touche Ctrl

Voir aussi