Exemplarische Vorgehensweise: Aktivieren der Drag & Drop-Funktion auf einem Benutzersteuerelement

In dieser exemplarische Vorgehensweise wird veranschaulicht, wie man ein benutzerdefiniertes Steuerelement erstellt, das an Drag & Drop-Datenübertragung in Windows Presentation Foundation (WPF) teilhat.

Mithilfe dieser exemplarische Vorgehensweise erstellen Sie ein benutzerdefiniertes WPF UserControl, das eine Kreisform darstellt. Sie werden dabei Funktionen für das Steuerelement implementieren, welche die Übertragung von Daten durch Drag & Drop ermöglichen. Wenn Sie z.B. von einem Kreis-Steuerelement auf ein anderes ziehen, werden die Füllfarbdaten vom Quellkreis auf den Zielkreis kopiert. Wenn Sie von einem Kreis-Steuerelement zu einem TextBox ziehen, wird die Repräsentation der Zeichenfolge der Farbfüllung zur TextBox kopiert. Sie werden zum Testen der Drag & Drop-Funktionalität zudem eine kleine Anwendung erstellen, die zwei Panel-Steuerelemente und eine TextBox enthält. Sie werden Code erstellen, der es den Panels ermöglicht, abgelegte Kreisdaten zu verarbeiten, sodass Sie Kreise aus der Auflistung untergeordneter Elemente von einem Panel zum anderen hin verschieben oder kopieren können.

In dieser exemplarischen Vorgehensweise werden die folgenden Aufgaben veranschaulicht:

  • Erstellen eines benutzerdefinierten Steuerelements.

  • Konfigurieren des benutzerdefinierten Steuerelements, sodass es als Quelle eines Ziehvorgangs dienen kann.

  • Konfigurieren des benutzerdefinierten Steuerelements, sodass es als Ziel eines Ablegevorgangs dienen kann.

  • Konfigurieren eines Panels, sodass es von dem Benutzersteuerelement abgelegte Daten empfangen kann.

Voraussetzungen

Für diese exemplarische Vorgehensweise benötigen Sie Visual Studio.

Erstellen Sie das Anwendungsprojekt

In diesem Abschnitt erstellen Sie die Infrastruktur der Anwendung, einschließlich einer Hauptseite mit zwei Panels und einer TextBox.

  1. Erstellen Sie ein neues WPF-Anwendungsprojekt in Visual Basic oder Visual C# mit dem Namen DragDropExample. Weitere Informationen finden Sie unter Exemplarische Vorgehensweise: Meine erste WPF-Desktopanwendung.

  2. Öffnen Sie „MainWindow.xaml“.

  3. Fügen Sie das folgende Markup zwischen dem Öffnen und Schließen der Grid-Tags hinzu.

    Dieses Markup erstellt die Benutzeroberfläche für die Testanwendung.

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

Fügen Sie ein neues Benutzersteuerelement zum Projekt hinzu

In diesem Abschnitt fügen Sie dem Projekt ein neues Benutzersteuerelement hinzu.

  1. Klicken Sie im Menü „Projekt” auf Benutzersteuerelement hinzufügen.

  2. Ändern Sie im Dialogfeld Neues Element hinzufügen den Namen in Circle.xaml und klicken Sie dann auf Hinzufügen.

    Circle.XAML und der dazugehörige CodeBehind werden dem Projekt hinzugefügt.

  3. Öffnen Sie Circle.xaml.

    Diese Datei enthält die Benutzeroberflächenelemente des Benutzersteuerelements.

  4. Fügen Sie das folgende Markup zum Stammelement Grid hinzu, um ein einfaches Benutzersteuerelement zu erstellen, dessen UI ein blauer Kreis ist.

    <Ellipse x:Name="circleUI" 
             Height="100" Width="100"
             Fill="Blue" />
    
  5. Öffnen Sie "Circle.Xaml.cs" oder "Circle.Xaml.vb".

  6. Fügen Sie in C# den folgenden Code nach dem Standardkonstruktor hinzu, um einen Kopierkonstruktor zu erstellen. Fügen Sie in Visual Basic den folgenden Code hinzu, um sowohl einen Standardkonstruktor als auch einen Kopierkonstruktor zu erstellen.

    Fügen Sie eine Kopierkonstruktor-Methode in die CodeBehind-Datei ein, damit das Benutzersteuerelement kopiert werden kann. Im vereinfachten kreisförmigen Benutzersteuerelement wollen wir nur die Füllfarbe und die Größe des Benutzersteuerelements kopieren.

    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
    

So fügen Sie das Benutzersteuerelement dem Hauptfenster hinzu

  1. Öffnen Sie „MainWindow.xaml“.

  2. Fügen Sie das folgende XAML dem öffnenden Window-Tag hinzu, um einen XML-Namespace-Verweis auf die aktuelle Anwendung zu erstellen.

    xmlns:local="clr-namespace:DragDropExample"
    
  3. Fügen Sie Im ersten StackPanel das folgende XAML hinzu, um zwei Instanzen des Kreis-Benutzersteuerelements im ersten Panel zu erzeugen.

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

    Der vollständige XAML-Code für das Panel sieht folgendermaßen aus.

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

Implementieren der Ereignisse der Ziehquelle im Benutzersteuerelement

In diesem Abschnitt überschreiben Sie die OnMouseMove-Methode und initiieren den Drag & Drop-Vorgang.

Wenn ein Ziehvorgang gestartet wird (eine Maustaste wird gedrückt und die Maus bewegt sich), verpacken Sie die zu übertragenden Daten in ein DataObject. In diesem Fall wird das Kreis-Steuerelement drei Datenelemente verpacken: eine Zeichenfolgendarstellung seiner Füllfarbe, eine double-Darstellung seiner Höhe und eine Kopie von sich selbst.

Initiieren eines Drag & Drop-Vorgangs

  1. Öffnen Sie "Circle.Xaml.cs" oder "Circle.Xaml.vb".

  2. Fügen Sie die folgende OnMouseMove-Überschreibung hinzu, um die Klassenbehandlung für das MouseMove-Ereignis zur Verfügung zu stellen.

    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
    

    Dieser OnMouseMove überschreibt die folgenden Aufgaben:

    • Überprüft, ob die linke Maustaste gedrückt wird, während sich die Maus bewegt.

    • Verpacken der Kreis-Daten in ein DataObject. In diesem Fall verpackt das Kreis-Steuerelement drei Datenelemente: eine Zeichenfolgendarstellung seiner Füllfarbe, eine double-Darstellung seiner Höhe und eine Kopie von sich selbst.

    • Ruft die statistische DragDrop.DoDragDrop-Methode auf, um den Drag & Drop-Vorgang auszulösen. Die übergeben die folgenden drei Parameter an die DoDragDrop-Methode:

      • dragSource: Ein Verweis auf dieses Steuerelement.

      • data - Die DataObject wurde im vorherigen Code erstellt.

      • allowedEffects – Die zulässigen Drag-and-Drop-Vorgänge, die Copy oder Move sind.

  3. Drücken Sie F5, um die Anwendung zu erstellen und auszuführen.

  4. Klicken Sie auf eines der Kreis-Steuerelemente und ziehen Sie es über die Panels, den anderen Kreis und die TextBox. Beim Ziehen über die TextBox ändert sich der Cursor, um eine Bewegung anzuzeigen.

  5. Beim Zeihen eines Kreises über die TextBox drücken Sie die Strg-Taste. Beachten Sie, wie sich der Cursor ändert, um einen Kopiervorgang anzuzeigen.

  6. Drag & Drop eines Kreises auf die TextBox. Die Zeichenfolgendarstellung der Füllfarbe des Kreises wird dem Inhalt der TextBox angefügt.

    String representation of Circle's fill color

Standardmäßig ändert sich der Cursor während eines Drag & Drop-Vorgangs, um anzuzeigen, welche Auswirkungen das Ablegen der Daten hat. Sie können mithilfe des GiveFeedback-Ereignisses einen anderen Cursor festlegen und bestimmen, welches Feedback an den Benutzer gegeben werden soll.

Feedback an den Benutzer geben

  1. Öffnen Sie "Circle.Xaml.cs" oder "Circle.Xaml.vb".

  2. Fügen Sie die folgende OnGiveFeedback-Überschreibung hinzu, um die Klassenbehandlung für das GiveFeedback-Ereignis zur Verfügung zu stellen.

    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
    

    Dieser OnGiveFeedback überschreibt die folgenden Aufgaben:

    • Überprüfen Sie die Effects-Werte, die im DragOver des Ablageziels des Ereignishandlers eingestellt sind.

    • Stellt einen benutzerdefinierten Cursor auf den Effects-Wert ein. Der Cursor soll visuelles Feedback an den Benutzer geben, welche Auswirkungen das Ablegen der Daten hat.

  3. Drücken Sie F5, um die Anwendung zu erstellen und auszuführen.

  4. Ziehen Sie eines der Kreis-Steuerelemente über das Panel, den anderen Kreis und die TextBox. Beachten Sie, dass die Cursor jetzt die von Ihnen in der OnGiveFeedback-Überschreibung festgelegten benutzerdefinierten Cursor sind.

    Drag and drop with custom cursors

  5. Markieren Sie den Text green aus dem TextBox.

  6. Ziehen Sie den Text green auf ein Kreis-Steuerelement. Beachten Sie, dass die standardmäßigen Cursor angezeigt werden, um die Auswirkungen des Drag & Drop-Vorgangs anzugeben. Der Feedbackcursor wird immer durch die Quelle des Ziehvorgangs festgelegt.

Implementieren Sie die Ereignisse des Ablageziels im Benutzersteuerelement

In diesem Abschnitt geben Sie an, dass das Benutzersteuerelement ein Ablageziel ist, überschreiben die Methoden, die das Benutzersteuerelement befähigen, ein Ablageziel sein und verarbeiten die Daten, die darauf abgelegt werden.

So konfigurieren Sie das Benutzersteuerelement als Ziel eines Ablegevorgangs

  1. Öffnen Sie Circle.xaml.

  2. Fügen Sie im öffnenden UserControl-Tag die AllowDrop-Eigenschaft hinzu und stellen Sie sie auf true ein.

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

Die OnDrop-Methode wird aufgerufen, wenn die AllowDrop-Eigenschaft auf true eingestellt ist, und Daten werden aus der Ziehquelle auf das Kreis-Benutzersteuerelement gezogen. In dieser Methode verarbeiten Sie die Daten, die abgelegt wurden und wenden sie auf den Kreis an.

So verarbeiten Sie die abgelegten Daten

  1. Öffnen Sie "Circle.Xaml.cs" oder "Circle.Xaml.vb".

  2. Fügen Sie die folgende OnDrop-Überschreibung hinzu, um die Klassenbehandlung für das Drop-Ereignis zur Verfügung zu stellen.

    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
    

    Dieser OnDrop überschreibt die folgenden Aufgaben:

    • Verwendet die GetDataPresent-Methode, um zu überprüfen, ob die gezogenen Daten ein Zeichenfolgeobjekt enthalten.

    • Verwendet die GetData-Methode, um die Zeichenfolgedaten zu entpacken, wenn sie vorhanden sind.

    • Verwendet eine BrushConverter, um zu versuchen, eine Zeichenfolge in ein Brush zu konvertieren.

    • Wenn die Konvertierung erfolgreich ist, wende den Pinsel auf die Fill der Ellipse an, den die UI des Kreis-Steuerelements zur Verfügung stellt.

    • Markiert das Drop-Ereignis als behandelt. Sie sollten das Drop-Ereignis als behandelt kennzeichnen, damit andere Elemente, die dieses Ereignis empfangen, wissen, dass das Kreis-Steuerelement es behandelt hat.

  3. Drücken Sie F5, um die Anwendung zu erstellen und auszuführen.

  4. Wählen Sie den Text green in der TextBox aus.

  5. Ziehen Sie den Text auf ein Kreis-Steuerelement, und legen Sie ihn ab. Der Kreis ändert sich von Blau in Grün.

    Convert a string to a brush

  6. Geben Sie den Text green in den TextBox ein.

  7. Wählen Sie den Text gre in der TextBox aus.

  8. Ziehen Sie ihn auf ein Kreis-Steuerelement, und legen Sie ihn ab. Beachten Sie, dass sich zwar der Cursor ändert, um anzuzeigen, dass der Ablegevorgang zulässig ist, die Farbe des Kreises sich aber nicht ändert, da gre keine gültige Farbe ist.

  9. Ziehen Sie vom grünen Kreis-Steuerelement auf das blaue Kreis-Steuerelement. Der Kreis ändert sich von Blau in Grün. Beachten Sie, dass der jeweils angezeigte Cursor davon abhängt, ob die TextBox oder der Kreis die Quelle des Ziehvorgangs ist.

Um ein Element zu einem Ablageziel zu machen, genügt das Festlegen der AllowDrop-Eigenschaft auf true und das Verarbeiten der abgelegten Daten. Um jedoch eine bessere Benutzererfahrung zu erreichen, sollten Sie auch die DragEnter-, DragLeave- und DragOver-Ereignisse behandeln. In diesen Ereignissen können Sie vor Ablage der Daten diese überprüfen und zusätzliches Feedback für den Benutzer bereitstellen.

Wenn Daten über das Kreis-Steuerelement gezogen werden, sollte das Steuerelement die Quelle des Ziehvorgangs darüber benachrichtigen, ob die darüber gezogenen Daten verarbeitet werden können. Wenn das Steuerelement nicht weiß, wie die Daten zu verarbeiten sind, sollte es den Ablegevorgang ablehnen. Dazu behandeln Sie das DragOver-Ereignis und legen die Effects-Eigenschaft fest.

So stellen sie sicher, dass die Datenablage zulässig ist

  1. Öffnen Sie "Circle.Xaml.cs" oder "Circle.Xaml.vb".

  2. Fügen Sie die folgende OnDragOver-Überschreibung hinzu, um die Klassenbehandlung für das DragOver-Ereignis zur Verfügung zu stellen.

    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
    

    Diese OnDragOver-Überschreibung führt die folgenden Aufgaben aus:

    • Legt die Effects-Eigenschaft auf None fest.

    • Führt die gleichen Überprüfungen durch, die in der OnDrop-Methode durchgeführt werden, um zu bestimmen, ob das Kreis-Steuerelement die gezogenen Daten verarbeiten kann.

    • Wenn das Benutzersteuerelement die Daten verarbeiten kann, stellen Sie die Effects-Eigenschaft auf Copy oder Move ein.

  3. Drücken Sie F5, um die Anwendung zu erstellen und auszuführen.

  4. Wählen Sie den Text gre in der TextBox aus.

  5. Ziehen Sie den Text auf ein Kreis-Steuerelement. Beachten Sie, dass sich der Cursor jetzt so ändert, dass er anzeigt, dass der Ablegevorgang nicht zulässig ist, da gre keine gültige Farbe ist.

Sie können die Benutzerfunktionalität weiter verbessern, indem Sie eine Vorschau des Drop-Vorgangs anwenden. Für das Kreis-Benutzersteuerelement überschreiben Sie die OnDragEnter- und OnDragLeave-Methode. Wenn die Daten über das Steuerelement gezogen werden, wird die aktuelle Hintergrundfarbe Fill in einer Platzhaltervariablen gespeichert. Die Zeichenfolge wird dann in einen Pinsel konvertiert und auf das Ellipse angewendet, das die UI des Kreises bereitstellt. Werden die Daten aus dem Kreis herausgezogen, ohne vorher abgelegt worden zu sein, wird der ursprüngliche Fill-Wert wieder auf den Kreis angewendet.

So können Sie die Auswirkungen eines Drag & Drop-Vorgangs in der Vorschau anzeigen

  1. Öffnen Sie "Circle.Xaml.cs" oder "Circle.Xaml.vb".

  2. Deklarieren Sie in der Kreis-Klasse eine private Brush-Variable namens _previousFill und initialisieren Sie diese mit null.

    public partial class Circle : UserControl
    {
        private Brush _previousFill = null;
    
    Public Class Circle
        Private _previousFill As Brush = Nothing
    
  3. Fügen Sie die folgende OnDragEnter-Überschreibung hinzu, um die Klassenbehandlung für das DragEnter-Ereignis zur Verfügung zu stellen.

    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
    

    Diese OnDragEnter-Überschreibung führt die folgenden Aufgaben aus:

    • Speichert die Fill-Eigenschaft der Ellipse in der _previousFill-Variablen.

    • Führt die gleichen Überprüfungen durch, die in der OnDrop-Methode durchgeführt werden, um zu bestimmen, ob das Kreis-Steuerelement die gezogenen Daten in einer Brush verarbeiten kann.

    • Wenn die Daten in ein gültiges Brush konvertiert werden, wendet sie auf die Fill derEllipse an.

  4. Fügen Sie die folgende OnDragLeave-Überschreibung hinzu, um die Klassenbehandlung für das DragLeave-Ereignis zur Verfügung zu stellen.

    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
    

    Diese OnDragLeave-Überschreibung führt die folgenden Aufgaben aus:

    • Wendet die in der Variabel _previousFill gespeicherte Brush auf die Fill der Ellipse an, die die UI des Kreis-Benutzeroberfläche zur Verfügung stellt.
  5. Drücken Sie F5, um die Anwendung zu erstellen und auszuführen.

  6. Wählen Sie den Text green in der TextBox aus.

  7. Ziehen Sie den Text über ein Kreis-Steuerelement ohne ihn abzulegen. Der Kreis ändert sich von Blau in Grün.

    Preview the effects of a drag-and-drop operation

  8. Ziehen Sie den Text vom Kreis-Steuerelement weg. Der Kreis ändert sich von Grün zurück in Blau.

Ermöglichen Sie einem Panel, abgelegte Daten zu empfangen

In diesem Abschnitt werden Sie den Panels, die die Kreis-Steuerelemente hosten, ermöglichen, als Ziele für gezogene Kreisdaten zu fungieren. Sie werden den Code implementieren, der es Ihnen ermöglicht, einen Kreis von einem Panel in ein anderes zu verschieben, oder eine Kopie eines Kreis-Steuerelements zu erstellen, indem Sie die STRG-Taste gedrückt halten, während Sie einen Kreis ziehen und ablegen.

  1. Öffnen Sie „MainWindow.xaml“.

  2. Wie in dem folgenden XAML gezeigt wird, werden in jeder der StackPanel-Steuerelemente in den DragOver und Drop-Ereignissen Handler hinzugefügt. Benennen Sie den DragOver-Ereignishandler, panel_DragOver, und benennen Sie den Drop-Ereignishandler, panel_Drop.

    Standardmäßig sind die Panels keine Ablageziele. Um sie zu aktivieren, fügen Sie die AllowDrop-Eigenschaft beiden Panels hinzu, und legen Sie den Wert auf true fest.

    <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. Öffnen Sie „MainWindow.xaml.cs“ bzw. „MainWindow.xaml.vb“.

  4. Fügen Sie dem DragOver-Ereignishandler folgenden Code hinzu.

    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
    

    Dieser DragOver-Ereignishandler führt die folgenden Aufgaben aus:

    • Überprüft, ob die gezogenen Daten die „Objekt”-Daten enthalten, die vom Kreis-Steuerelement in das DataObject verpackt und beim Aufruf von DoDragDrop übergeben wurden.

    • Überprüft, ob die Strg-Taste gedrückt wird, falls die „Objekt”-Daten vorhanden sind.

    • Wenn die Strg-Taste gedrückt wird, wird die Effects-Eigenschaft auf Copy eingestellt. Legen Sie dazu ansonsten die Effects-Eigenschaft auf Move fest.

  5. Fügen Sie dem Drop-Ereignishandler folgenden Code hinzu.

    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
    

    Dieser Drop-Ereignishandler führt die folgenden Aufgaben aus:

    • Überprüft, ob das Drop-Ereignis schon behandelt wurde. Wird etwa ein Kreis auf einem anderen Kreis abgelegt, der das Drop-Ereignis behandelt, soll das Panel, das den Kreis enthält, dieses Ereignis nicht zusätzlich behandeln.

    • Überprüft, ob die Strg-Taste gedrückt ist, falls das Drop-Ereignis nicht behandelt wird.

    • Wenn die Strg-Taste gedrückt ist, während Drop passiert, wird eine Kopie des Kreis-Steuerelements gemacht und zur Children-Auflistung der StackPanel hinzugefügt.

    • Wenn die Strg-Taste nicht gedrückt ist, bewegt sich der Cursor von der Children-Auflistung zu seinem übergeordneten Panel der Children-Auflistung des Panels, zu dem es gezogen wurde.

    • Stellen Sie die Effects-Eigenschaft ein, um die DoDragDrop-Methode zu benachrichtigen, ob ein Bewegungs- oder Kopiervorgang ausgeführt wurde.

  6. Drücken Sie F5, um die Anwendung zu erstellen und auszuführen.

  7. Markieren Sie den Text green aus dem TextBox.

  8. Ziehen Sie den Text auf ein Kreis-Steuerelement, und legen Sie ihn ab.

  9. Ziehen Sie ein Kreis-Steuerelement vom linken Panel in das rechte Panel und legen Sie es ab. Der Kreis wird aus der Children-Auflistung des linken Panels entfernt und der Auflistung untergeordneter Elemente des rechten Panels hinzugefügt.

  10. Ziehen Sie ein Kreis-Steuerelement aus dem Panel, in dem es sich befindet, in das andere Panel und legen Sie es bei gedrückter Strg-Taste ab. Der Kreis wird kopiert und die Kopie der Children-Auflistung des empfangenden Panels hinzugefügt.

    Dragging a Circle while pressing the CTRL key

Siehe auch