Udostępnij za pośrednictwem


Przewodnik: Włączanie przeciągania i upuszczania na kontrolce użytkownika

W tym przewodniku pokazano, jak utworzyć niestandardową kontrolkę użytkownika, która może uczestniczyć w przeciąganiu i upuszczaniu transferu danych w programie Windows Presentation Foundation (WPF).

W tym przewodniku utworzysz niestandardowy element WPF UserControl, który reprezentuje kształt koła. Zaimplementujesz funkcje kontrolki, aby umożliwić transfer danych przez przeciąganie i upuszczanie. Jeśli na przykład przeciągniesz z jednej kontrolki Circle do innej, dane koloru wypełnienia są kopiowane ze źródłowego okręgu do miejsca docelowego. Jeśli przeciągniesz z kontrolki Circle do TextBox, do TextBoxzostanie skopiowany łańcuch znaków reprezentujący kolor wypełnienia. Utworzysz również małą aplikację zawierającą dwie kontrolki panelu i TextBox, aby przetestować funkcjonalność przeciągania i upuszczania. Napiszesz kod, który umożliwia panelom przetwarzanie upuszczonych danych okręgów, co pozwoli na przenoszenie lub kopiowanie okręgów z kolekcji elementów podrzędnych jednego panelu do drugiego.

W tym przewodniku przedstawiono następujące zadania:

  • Utwórz niestandardową kontrolkę użytkownika.

  • Umożliwianie kontrolki użytkownika jako źródła przeciągania.

  • Umożliw kontrolce użytkownika działanie jako element docelowy upuszczania.

  • Umożliwia panelowi odbieranie danych przeciągniętych do niego z kontrolki użytkownika.

Warunki wstępne

Aby ukończyć ten przewodnik, potrzebny jest program Visual Studio.

Tworzenie projektu aplikacji

W tej sekcji utworzysz infrastrukturę aplikacji, która zawiera stronę główną z dwoma panelami i elementem TextBox.

  1. Utwórz nowy projekt aplikacji WPF w Visual Basic lub Visual C# o nazwie DragDropExample. Aby uzyskać więcej informacji, zobacz Walkthrough: My first WPF desktop application.

  2. Otwórz plik MainWindow.xaml.

  3. Dodaj następujący znacznik między znacznikami otwierania i zamykania Grid.

    Ten znacznik tworzy interfejs użytkownika dla aplikacji testowej.

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

Dodawanie nowej kontrolki użytkownika do projektu

W tej sekcji dodasz nową kontrolkę użytkownika do projektu.

  1. W menu Projekt wybierz pozycję Dodaj kontrolę użytkownika.

  2. W oknie dialogowym Dodawanie nowego elementu zmień nazwę na Circle.xaml, a następnie kliknij przycisk Dodaj.

    Plik Circle.xaml i jego powiązany kod są dodane do projektu.

  3. Otwórz plik Circle.xaml.

    Ten plik będzie zawierać elementy interfejsu użytkownika kontrolki użytkownika.

  4. Dodaj następujący znacznik do korzenia Grid, aby utworzyć prostą kontrolkę, która ma niebieski okrąg w interfejsie użytkownika.

    <Ellipse x:Name="circleUI" 
             Height="100" Width="100"
             Fill="Blue" />
    
  5. Otwórz Circle.xaml.cs lub Circle.xaml.vb.

  6. W języku C# dodaj następujący kod po konstruktorze bez parametrów, aby utworzyć konstruktor kopiujący. W języku Visual Basic dodaj następujący kod, aby utworzyć zarówno konstruktor bez parametrów, jak i konstruktor kopiujący.

    Aby umożliwić skopiowanie kontrolki, należy dodać metodę konstruktora kopiującego w pliku code-behind. W uproszczonej kontrolce użytkownika Circle skopiujesz tylko kontrolkę Fill i rozmiar kontrolki użytkownika.

    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
    

Dodawanie kontrolki użytkownika do okna głównego

  1. Otwórz plik MainWindow.xaml.

  2. Dodaj następujący kod XAML do tagu otwierającego Window, aby utworzyć odwołanie przestrzeni nazw XML do bieżącej aplikacji.

    xmlns:local="clr-namespace:DragDropExample"
    
  3. W pierwszym StackPaneldodaj następujący kod XAML, aby utworzyć dwa wystąpienia kontrolki użytkownika Circle w pierwszym panelu.

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

    Pełny kod XAML dla panelu wygląda następująco.

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

Implementowanie przeciągania zdarzeń źródłowych w kontrolce użytkownika

W tej sekcji zastąpisz metodę OnMouseMove i zainicjujesz operację przeciągania i upuszczania.

Jeśli przeciąganie zostanie uruchomione (naciśnięcie przycisku myszy i przeniesienie myszy), spakujesz dane, które mają zostać przesłane do DataObject. W takim przypadku kontrolka Circle spakuje trzy elementy danych; reprezentacja ciągu koloru wypełnienia, podwójna reprezentacja wysokości i kopia samego siebie.

Aby zainicjować operację przeciągania i upuszczania

  1. Otwórz Circle.xaml.cs lub Circle.xaml.vb.

  2. Dodaj następujące OnMouseMove nadpisanie, aby zapewnić obsługę klasy dla zdarzenia 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
    

    To przesłonięcie OnMouseMove wykonuje następujące zadania:

    • Sprawdza, czy lewy przycisk myszy jest naciśnięty podczas przesuwania myszy.

    • Pakuje dane okręgu do DataObject. W takim przypadku kontrolka Circle pakuje trzy elementy danych; reprezentacja ciągu koloru wypełnienia, podwójna reprezentacja wysokości i kopia samego siebie.

    • Wywołuje metodę statyczną DragDrop.DoDragDrop, aby rozpocząć operację przeciągania i upuszczania. Następujące trzy parametry należy przekazać do metody DoDragDrop:

      • dragSource — odwołanie do tej kontrolki.

      • dataDataObject utworzona w poprzednim kodzie.

      • allowedEffects — dozwolone operacje przeciągania i upuszczania, które są Copy lub Move.

  3. Naciśnij F5, aby skompilować i uruchomić aplikację.

  4. Kliknij jedną z kontrolek Circle i przeciągnij ją na panele, drugi okrąg i TextBox. Podczas przeciągania nad TextBox, kursor zmienia się, aby wskazać przesunięcie.

  5. Podczas przeciągania koła po TextBox, naciśnij klawisz Ctrl. Zwróć uwagę, że kursor zmienia się, aby wskazać kopię.

  6. Przeciągnij i upuść okrąg na TextBox. Reprezentacja tekstowa koloru wypełnienia Circle jest dołączana do TextBox.

    reprezentacja ciągu koloru wypełnienia okręgu

Domyślnie kursor zmieni się podczas operacji przeciągania i upuszczania, aby wskazać, jakie będą skutki upuszczenia danych. Opinie przekazane użytkownikowi można dostosować, obsługując zdarzenie GiveFeedback i ustawiając inny kursor.

Prześlij opinię użytkownikowi

  1. Otwórz Circle.xaml.cs lub Circle.xaml.vb.

  2. Należy dodać następujące przesłonięcie OnGiveFeedback, aby obsłużyć klasę na zdarzenie 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
    

    To nadpisanie OnGiveFeedback wykonuje następujące zadania:

    • Sprawdza wartości Effects ustawione w procedurze obsługi zdarzeń DragOver obiektu docelowego upuszczania.

    • Ustawia kursor niestandardowy na podstawie wartości Effects. Kursor ma na celu danie wizualnej informacji zwrotnej użytkownikowi o tym, jaki będzie efekt upuszczenia danych.

  3. Naciśnij F5, aby skompilować i uruchomić aplikację.

  4. Przeciągnij jedną z kontrolki Circle na panele, drugą kontrolkę Circle oraz TextBox. Zwróć uwagę, że kursory są teraz kursorami niestandardowymi określonymi w OnGiveFeedback przesłonięcia.

    przeciąganie i upuszczanie za pomocą niestandardowych kursorów

  5. Wybierz tekst green z TextBox.

  6. Przeciągnij tekst green do kontrolki Circle. Zwróć uwagę, że domyślne kursory są wyświetlane w celu wskazania efektów operacji przeciągania i upuszczania. Kursor zwrotny jest zawsze ustawiany przez źródło przeciągnięcia.

Implementowanie zdarzeń miejsca docelowego upuszczania w kontrolce użytkownika

W tej sekcji określisz, że element sterujący użytkownika jest miejscem docelowym upuszczania, nadpiszesz metody, które umożliwiają elementowi sterującemu być miejscem docelowym upuszczania, i przetworzysz dane, które są na nim upuszczane.

Aby umożliwić elementowi sterującemu działanie jako cel upuszczania

  1. Otwórz plik Circle.xaml.

  2. W tagu otwierającego UserControl dodaj właściwość AllowDrop i ustaw ją na wartość 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">
    

Metoda OnDrop jest wywoływana, gdy właściwość AllowDrop jest ustawiona na true, a dane ze źródła przeciągania są upuszczane na kontrolkę użytkownika Circle. W tej metodzie przetworzysz dane, które zostały porzucone i zastosujesz dane do okręgu.

Aby przetworzyć upuszczone dane

  1. Otwórz Circle.xaml.cs lub Circle.xaml.vb.

  2. Dodaj następujące OnDrop nadpisanie, aby zapewnić obsługę klasy dla zdarzenia 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
    

    To przesłonięcie OnDrop wykonuje następujące zadania:

    • Używa metody GetDataPresent, aby sprawdzić, czy przeciągane dane zawierają obiekt ciągu.

    • Używa metody GetData, aby wyodrębnić dane ciągu, jeśli są obecne.

    • Używa BrushConverter, aby spróbować przekonwertować ciąg na Brush.

    • Jeśli konwersja zakończy się pomyślnie, zastosuj pędzel do Fill elementu Ellipse, który zapewnia interfejs użytkownika dla kontrolki Circle.

    • Oznacza zdarzenie Drop jako obsługiwane. Powinieneś oznaczyć zdarzenie upuszczania jako obsłużone, aby inne elementy, które odbierają to zdarzenie, wiedziały, że kontrolka Circle je obsłużyła.

  3. Naciśnij F5, aby skompilować i uruchomić aplikację.

  4. Wybierz tekst green w TextBox.

  5. Przeciągnij tekst do kontrolki Okrąg i upuść go. Okrąg zmienia się z niebieskiego na zielony.

    Konwertowanie ciągu na pędzel

  6. Wpisz tekst green w TextBox.

  7. Wybierz tekst gre w TextBox.

  8. Przeciągnij ją do kontrolki Okrąg i upuść ją. Zwróć uwagę, że kursor zmienia się, aby wskazać, że upuszczanie jest dozwolone, ale kolor okręgu nie zmienia się, ponieważ gre nie jest prawidłowym kolorem.

  9. Przeciągnij z zielonego przycisku Circle i upuść na niebieski przycisk Circle. Okrąg zmienia się z niebieskiego na zielony. Zwróć uwagę, że to, który kursor jest wyświetlany, zależy od tego, czy TextBox, czy Circle jest źródłem przeciągania.

Ustawienie właściwości AllowDrop na true i przetwarzanie upuszczonych danych jest wszystkim, co jest wymagane, aby umożliwić elementowi stanie się miejscem docelowym upuszczania. Jednak aby zapewnić lepsze środowisko użytkownika, należy również obsługiwać zdarzenia DragEnter, DragLeavei DragOver. W takich sytuacjach można przeprowadzić sprawdzenia i dostarczyć użytkownikowi dodatkowe informacje zwrotne, zanim dane zostaną porzucone.

Gdy dane są przeciągane przez kontrolkę użytkownika Circle, kontrolka powinna powiadomić źródło przeciągania, czy może przetwarzać przeciągane dane. Jeśli kontrolka nie wie, jak przetwarzać dane, powinna odmówić ich przyjęcia. W tym celu obsłużysz zdarzenie DragOver i ustawisz właściwość Effects.

Aby sprawdzić, czy upuszczanie danych jest dozwolone

  1. Otwórz Circle.xaml.cs lub Circle.xaml.vb.

  2. Dodaj następujące nadpisanie OnDragOver, aby umożliwić obsługę klasy dla zdarzenia 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
    

    Ten OnDragOver mechanizm przesłonięcia wykonuje następujące zadania:

    • Ustawia właściwość Effects na wartość None.

    • Wykonuje te same kontrole, które są wykonywane w metodzie OnDrop, aby określić, czy kontrolka użytkownika Circle może przetwarzać przeciągane dane.

    • Jeśli kontrolka użytkownika może przetwarzać dane, ustawia właściwość Effects na wartość Copy lub Move.

  3. Naciśnij F5, aby skompilować i uruchomić aplikację.

  4. Wybierz tekst gre w TextBox.

  5. Przeciągnij tekst do elementu kontrolnego z kształtem koła. Zwróć uwagę, że kursor zmienia się, wskazując, że upuszczanie jest niedozwolone, ponieważ gre nie jest prawidłowym kolorem.

Możesz jeszcze bardziej poprawić doświadczenie użytkownika, stosując podgląd operacji przeciągania. W przypadku kontrolki użytkownika Circle zastąpisz metody OnDragEnter i OnDragLeave. Po przeciągnięciu danych przez kontrolkę bieżące tło Fill jest zapisywane w zmiennej zastępczej. Ciąg jest następnie konwertowany na pędzel i stosowany na Ellipse, stanowiący część interfejsu użytkownika Circle. Jeśli dane są przeciągane z okręgu bez porzucania, oryginalna wartość Fill zostanie ponownie zastosowana do okręgu.

Aby wyświetlić podgląd efektów operacji przeciągania i upuszczania

  1. Otwórz Circle.xaml.cs lub Circle.xaml.vb.

  2. W klasie Circle zadeklaruj prywatną zmienną Brush o nazwie _previousFill i zainicjuj ją na wartość null.

    public partial class Circle : UserControl
    {
        private Brush _previousFill = null;
    
    Public Class Circle
        Private _previousFill As Brush = Nothing
    
  3. Dodaj następujące OnDragEnter nadpisanie, aby zapewnić obsługę zdarzenia DragEnter przez klasę.

    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
    

    Ta przesłona OnDragEnter wykonuje następujące zadania:

    • Zapisuje właściwość Fill obiektu Ellipse w zmiennej _previousFill.

    • Wykonuje te same kontrole, które są wykonywane w metodzie OnDrop, aby określić, czy dane można przekonwertować na Brush.

    • Jeśli dane zostaną przekonwertowane na prawidłowy Brush, przypisuje je do FillEllipse.

  4. Dodaj następujące OnDragLeave nadpisania w celu zapewnienia obsługi klasy dla zdarzenia 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
    

    To zastąpienie OnDragLeave wykonuje następujące zadania:

    • Stosuje Brush zapisane w zmiennej _previousFill do Fill w Ellipse, która zapewnia interfejs użytkownika kontrolki Circle.
  5. Naciśnij F5, aby skompilować i uruchomić aplikację.

  6. Wybierz tekst green w TextBox.

  7. Przeciągnij tekst nad kontrolką Circle bez upuszczania. Okrąg zmienia się z niebieskiego na zielony.

    podgląd efektów operacji przeciągania i upuszczania

  8. Przeciągnij tekst z dala od kontrolki Circle. Okrąg zmienia się z zielonego z powrotem na niebieski.

Włącz panel do odbierania przeniesionych danych

W tej sekcji włączysz panele obsługujące kontrolki użytkownika Circle, aby działały jako miejsca docelowe upuszczania dla przeciągniętych danych Circle. Zaimplementujesz kod, który umożliwia przeniesienie okręgu z jednego panelu do innego lub utworzenie kopii kontrolki Circle przez przytrzymanie Ctrl podczas przeciągania i upuszczania okręgu.

  1. Otwórz plik MainWindow.xaml.

  2. Jak pokazano w poniższym kodzie XAML, w każdym z kontrolek StackPanel dodaj programy obsługi dla zdarzeń DragOver i Drop. Nazwij program obsługi zdarzeń DragOver, panel_DragOveri nadaj programowi obsługi zdarzeń Drop nazwę panel_Drop.

    Domyślnie panele nie są miejscami docelowymi. Aby je włączyć, dodaj właściwość AllowDrop do obu paneli i ustaw wartość na 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. Otwórz MainWindows.xaml.cs lub MainWindow.xaml.vb.

  4. Dodaj następujący kod dla programu obsługi zdarzeń 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
    

    Ta procedura obsługi zdarzeń DragOver wykonuje następujące zadania:

    • Sprawdza, czy przeciągane dane zawierają dane "Object", które zostały spakowane w DataObject przez kontrolkę użytkownika Circle i przekazane w wywołaniu do DoDragDrop.

    • Jeśli dane "Object" są obecne, sprawdza, czy klawisz Ctrl oznaczony jako jest wciśnięty.

    • Jeśli zostanie naciśnięty klawisz Ctrl, ustaw właściwość Effects na Copy. W przeciwnym razie ustaw właściwość Effects na Move.

  5. Dodaj następujący kod dla programu obsługi zdarzeń 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
    

    Ta procedura obsługi zdarzeń Drop wykonuje następujące zadania:

    • Sprawdza, czy zdarzenie Drop zostało już obsłużone. Jeśli na przykład okrąg zostanie porzucony na innym okręgu, który obsługuje zdarzenie Drop, nie chcesz, aby panel zawierający koło również go obsłużył.

    • Jeśli zdarzenie Drop nie jest obsługiwane, sprawdza, czy klawisz Ctrl jest wciśnięty.

    • Jeśli klawisz Ctrl jest naciskany, gdy występuje Drop, utwórz kopię kontrolki Circle i dodaj ją do kolekcji Children elementu StackPanel.

    • Jeśli Ctrl nie jest naciśnięty, przenosi Okrąg z kolekcji Children panelu nadrzędnego do kolekcji Children panelu, na który został przeniesiony.

    • Ustawia właściwość Effects, aby powiadomić metodę DoDragDrop o tym, czy wykonano operację przenoszenia, czy kopiowania.

  6. Naciśnij F5, aby skompilować i uruchomić aplikację.

  7. Wybierz tekst green z TextBox.

  8. Przeciągnij tekst nad kontrolką Okrąg i upuść go.

  9. Przeciągnij kontrolkę Okrąg z lewego panelu do prawego panelu i upuść ją. Okrąg jest usuwany z kolekcji Children w panelu po lewej stronie i dodawany do kolekcji Dzieci w panelu po prawej stronie.

  10. Przeciągnij kontrolkę Circle z jednego panelu do drugiego i upuść ją, trzymając wciśnięty klawisz Ctrl. Okrąg jest kopiowany, a kopia jest dodawana do kolekcji Children panelu odbierającego.

    Przeciąganie koła z wciśniętym klawiszem CTRL

Zobacz też