Översikt över dra och släpp

Det här avsnittet innehåller en översikt över dra och släpp-stöd i WPF-program (Windows Presentation Foundation). Dra och släpp refererar ofta till en metod för dataöverföring som innebär att du använder en mus (eller någon annan pekenhet) för att markera ett eller flera objekt, dra dessa objekt över något önskat släppmål i användargränssnittet (användargränssnittet) och släppa dem.

Dra och släpp-stöd i WPF

Dra och släpp-åtgärder omfattar vanligtvis två parter: en dragkälla som det dragna objektet kommer ifrån och ett släppområde som tar emot det släppta objektet. Källan för dragning och släppmålet kan vara element i användargränssnittet i samma program eller i ett annat program.

Typen och antalet objekt som kan manipuleras med dra och släpp är helt godtyckligt. Till exempel är filer, mappar och val av innehåll några av de vanligaste objekten som manipuleras genom dra och släpp-åtgärder.

De specifika åtgärder som utförs under en dra och släpp-åtgärd är programspecifika och bestäms ofta av kontext. Om du till exempel drar ett urval av filer från en mapp till en annan på samma lagringsenhet flyttas filerna som standard, medan om du drar filer från en UNC-resurs (Universal Naming Convention) till en lokal mapp kopieras filerna som standard.

Funktionerna för dra och släpp som tillhandahålls av WPF är utformade för att vara mycket flexibla och anpassningsbara för att stödja en mängd olika dra-och-släpp-scenarier. Dra och släpp stöder manipulering av objekt i ett enda program eller mellan olika program. Dra och släppa mellan WPF-program och andra Windows-program stöds också fullt ut.

I WPF kan alla UIElement eller ContentElement delta i dra och släpp. De händelser och metoder som krävs för dra och släpp-åtgärder definieras i klassen DragDrop. Klasserna UIElement och ContentElement innehåller alias för de DragDrop kopplade händelserna så att händelserna visas i listan över klassmedlemmar när en UIElement eller ContentElement ärvs som ett baselement. Händelsehanterare som är kopplade till dessa händelser är anslutna till den underliggande bifogade händelsen DragDrop och tar emot samma instans av händelsedata. Mer information finns i händelsen UIElement.Drop.

Viktigt!

OLE-dra och släpp fungerar inte i internetzon.

Dataöverföring

Dra och släpp är en del av det mer allmänna området för dataöverföring. Dataöverföring omfattar åtgärder för att dra och släppa och kopiera och klistra in. En dra och släpp-åtgärd motsvarar en kopierings- och inklistrings- eller klipp-och-klistra-åtgärd som används för att överföra data från ett objekt eller program till ett annat med hjälp av systemets Urklipp. Båda typerna av åtgärder kräver:

  • Ett källobjekt som tillhandahåller data.

  • Ett sätt att tillfälligt lagra de överförda data.

  • Ett målobjekt som tar emot data.

I en kopierings- och inklistringsåtgärd används systemurklippet för att tillfälligt lagra överförda data; i en dra-och-släpp-åtgärd används en DataObject för att lagra data. Konceptuellt består ett dataobjekt av ett eller flera par av en Object som innehåller faktiska data och en motsvarande identifierare för dataformat.

Dragkällan initierar en dra-och-släpp-åtgärd genom att anropa den statiska metoden DragDrop.DoDragDrop och skicka den överförda datan till den. Metoden DoDragDrop omsluter automatiskt data i en DataObject om det behövs. Om du vill ha större kontroll över dataformatet kan du omsluta data i en DataObject innan du skickar dem till metoden DoDragDrop. Släppmålet ansvarar för att extrahera data från DataObject. Mer information om hur du arbetar med dataobjekt finns i Data- och dataobjekt.

Källan och målet för en dra och släpp-åtgärd är gränssnittselement. Men de data som faktiskt överförs har vanligtvis ingen visuell representation. Du kan skriva kod för att tillhandahålla en visuell representation av de data som dras, till exempel när filer dras i Utforskaren. Som standard ges feedback till användaren genom att markören ändras så att den representerar den effekt som dra och släpp-åtgärden kommer att ha på data, till exempel om data ska flyttas eller kopieras.

Dra och släpp-effekter

Dra och släpp-åtgärder kan ha olika effekter på de överförda data. Du kan till exempel kopiera data eller flytta data. WPF definierar en DragDropEffects uppräkning som du kan använda för att ange effekten av en dra och släpp-åtgärd. I dragkällan kan du ange vilka effekter källan ska tillåta i metoden DoDragDrop. I släppmålet kan du ange den effekt som målet avser i egenskapen Effects för klassen DragEventArgs. När släppmålet anger den avsedda effekten i händelsen DragOver skickas informationen tillbaka till dragkällan i GiveFeedback händelsen. Dra-källan använder den här informationen för att informera användaren om vilken effekt släppmålet avser att ha på data. När data tas bort anger släppmålet dess faktiska effekt i den Drop händelsen. Den informationen skickas tillbaka till dragkällan som returvärde för metoden DoDragDrop. Om släppmålet returnerar en effekt som inte finns i listan med dra källor för allowedEffectsavbryts dra och släpp-åtgärden utan att någon dataöverföring sker.

Det är viktigt att komma ihåg att i WPF används de DragDropEffects värdena endast för att tillhandahålla kommunikation mellan dragkällan och släppmålet när det gäller effekterna av dra och släpp-åtgärden. Den faktiska effekten av dra och släpp-åtgärden beror på att du skriver rätt kod i ditt program.

Släppmålet kan till exempel ange att effekten av att släppa data på den är att flytta data. Men om du vill flytta data måste de både läggas till i målelementet och tas bort från källelementet. Källelementet kan tyda på att det tillåter att data flyttas, men om du inte anger koden för att ta bort data från källelementet blir slutresultatet att data kopieras och inte flyttas.

Dra och släpp-händelser

Dra och släpp-åtgärder stöder en händelsedriven modell. Både dragkällan och släppmålet använder en standarduppsättning händelser för att hantera dra och släpp-åtgärder. Följande tabeller sammanfattar standardhändelserna för dra och släpp. Det här är kopplade händelser i klassen DragDrop. Mer information om bifogade händelser finns i Översikt över kopplade händelser.

Dra källhändelser

Evenemang Sammanfattning
GiveFeedback Den här händelsen inträffar kontinuerligt under en dra-och-släpp-åtgärd och gör det möjligt för släppkällan att ge feedbackinformation till användaren. Den här feedbacken ges ofta genom att ändra muspekarens utseende för att indikera de effekter som tillåts av släppmålet. Det här är en livlig händelse.
QueryContinueDrag Den här händelsen inträffar när tangentbords- eller musknappstillstånden ändras under en dra-och-släpp-åtgärd och gör att släppkällan kan avbryta drag-och-släpp-åtgärden beroende på nyckel-/knapptillstånd. Det här är en livlig händelse.
PreviewGiveFeedback Tunnelversion av GiveFeedback.
PreviewQueryContinueDrag Tunnelversion av QueryContinueDrag.

Släpp målhändelser

Evenemang Sammanfattning
DragEnter Den här händelsen inträffar när ett objekt dras in i släppmålets gräns. Det här är en livlig händelse.
DragLeave Den här händelsen inträffar när ett objekt dras ut från släppmålets gräns. Det här är en livlig händelse.
DragOver Den här händelsen inträffar kontinuerligt medan ett objekt dras (flyttas) inom släppmålets gräns. Det här är en livlig händelse.
Drop Den här händelsen inträffar när ett objekt släpps på släppmålet. Det här är en livlig händelse.
PreviewDragEnter Tunnelversion av DragEnter.
PreviewDragLeave Tunnelversion av DragLeave.
PreviewDragOver Tunnelversion av DragOver.
PreviewDrop Tunnelversion av Drop.

Om du vill hantera dra och släpp-händelser för instanser av ett objekt lägger du till hanterare för händelserna som anges i föregående tabeller. För att hantera dra och släpp-händelser på klassnivå, åsidosätt motsvarande virtuella On*Event- och On*PreviewEvent-metoder.

Implementera dra-och-släpp

Ett användargränssnittselement kan vara en dragningskälla, ett släppmål, eller båda delarna. Om du vill implementera grundläggande dra och släpp skriver du kod för att initiera dra och släpp-åtgärden och bearbeta borttagna data. Du kan förbättra dra och släpp-upplevelsen genom att hantera valfria dra och släpp-händelser.

Om du vill implementera grundläggande dra och släpp utför du följande uppgifter:

  • Identifiera elementet som ska vara en dragkälla. En dragkälla kan vara en UIElement eller en ContentElement.

  • Skapa en händelsehanterare på dra-källan som initierar dra och släpp-åtgärden. Händelsen är vanligtvis den typiska MouseMove-händelsen.

  • I händelsehanteraren för dragningskälla anropar du metoden DoDragDrop för att initiera dra-och-släpp-operationen. I DoDragDrop-anropet anger du dragkällan, de data som ska överföras och de tillåtna effekterna.

  • Identifiera elementet som ska vara ett släppmål. Ett släppmål kan vara UIElement eller ett ContentElement.

  • I släppmålet ställer du in egenskapen AllowDrop till true.

  • I släppmålet skapar du en Drop-händelsehanterare för att bearbeta släppta data.

  • I händelsehanteraren för Drop extraherar du data från DragEventArgs med hjälp av metoderna GetDataPresent och GetData.

  • I Drop händelsehanteraren använder du data för att utföra önskad dra-och-släpp-åtgärd.

Du kan förbättra din dra-och-släpp-implementering genom att skapa en anpassad DataObject och genom att hantera valfria dragsource- och släppmålhändelser, som visas i följande uppgifter:

  • Om du vill överföra anpassade data eller flera dataobjekt skapar du en DataObject som ska skickas till metoden DoDragDrop.

  • Om du vill utföra ytterligare åtgärder under ett drag hanterar du DragEnter, DragOveroch DragLeave händelser på släppmålet.

  • Om du vill ändra muspekarens utseende hanterar du händelsen GiveFeedback på dragkällan.

  • Om du vill ändra hur åtgärden dra och släpp avbryts, hantera QueryContinueDrag-händelsen på dragkällan.

Dra och släpp-exempel

I det här avsnittet beskrivs hur du implementerar dra och släpp för ett Ellipse-element. Ellipse är både en dragkälla och ett släppmål. De överförda data är strängrepresentationen av ellipsens Fill egenskap. Följande XAML visar Ellipse-elementet och de dra och släpp-relaterade händelser som det hanterar. Fullständiga steg om hur du implementerar dra och släpp finns i Genomgång: Aktivera dra och släpp på en användarkontroll.

<Ellipse Height="50" Width="50" Fill="Green"
     MouseMove="ellipse_MouseMove"
     GiveFeedback="ellipse_GiveFeedback"
     AllowDrop="True"
     DragEnter="ellipse_DragEnter" DragLeave="ellipse_DragLeave"
     DragOver="ellipse_DragOver" Drop="ellipse_Drop" />

Aktivera ett element för att vara en dragkälla

Ett objekt som är en dragkälla ansvarar för:

  • Identifiera när en dragning inträffar.

  • Initiering av dra-och-släpp-operationen.

  • Identifiera de data som ska överföras.

  • Ange de effekter som dra och släpp-åtgärden tillåts ha på de överförda data.

Dragkälla kan också ge feedback till användaren om de tillåtna åtgärderna (flytta, kopiera, ingen) och kan avbryta drag-och-släpp-åtgärden baserat på ytterligare användarinmatning, till exempel genom att trycka på ESC-tangenten under dragningen.

Det är programmets ansvar att avgöra när en drag inträffar och sedan initiera dra-och-släpp-åtgärden genom att anropa metoden DoDragDrop. Det här är vanligtvis när en MouseMove händelse inträffar över elementet som ska dras medan en musknapp trycks in. I följande exempel visas hur du initierar en dra-och-släpp-åtgärd från MouseMove händelsehanterare för ett Ellipse element för att göra det till en dragkälla. De överförda data är strängrepresentationen av ellipsens Fill egenskap.

private void ellipse_MouseMove(object sender, MouseEventArgs e)
{
    Ellipse ellipse = sender as Ellipse;
    if (ellipse != null && e.LeftButton == MouseButtonState.Pressed)
    {
        DragDrop.DoDragDrop( ellipse,
                             ellipse.Fill.ToString(),
                             DragDropEffects.Copy);
    }
}
Private Sub Ellipse_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Input.MouseEventArgs)
    Dim ellipse = TryCast(sender, Ellipse)
    If ellipse IsNot Nothing AndAlso e.LeftButton = MouseButtonState.Pressed Then
        DragDrop.DoDragDrop(ellipse, ellipse.Fill.ToString(), DragDropEffects.Copy)
    End If
End Sub

I händelsehanteraren för MouseMove anropar du metoden DoDragDrop för att initiera dra och släpp-åtgärden. Metoden DoDragDrop tar tre parametrar:

  • dragSource – En referens till beroendeobjektet som är källan till de överförda data. Detta är vanligtvis källan till händelsen MouseMove.

  • data – ett objekt som innehåller överförda data, omslutet i en DataObject.

  • allowedEffects – ett av de DragDropEffects uppräkningsvärden som anger de tillåtna effekterna av dra och släpp-åtgärden.

Alla serialiserbara objekt kan skickas i parametern data. Om data inte redan är omslutna i en DataObjectomsluts de automatiskt i en ny DataObject. Om du vill skicka flera dataobjekt måste du skapa DataObject själv och skicka det till metoden DoDragDrop. Mer information finns i data- och dataobjekt.

Parametern allowedEffects används för att ange vad dragningskällan tillåter att släppmålet gör med den överförda datan. De vanliga värdena för en dragkälla är Copy, Moveoch All.

Anmärkning

Släppmålet kan också ange vilka effekter det avser att åstadkomma som svar på data som har droppats. Om släppmålet till exempel inte känner igen datatypen som ska tas bort kan det neka data genom att ställa in dess tillåtna effekter på None. Den gör vanligtvis detta i sin DragOver händelsehanterare.

En dragkälla kan också hantera GiveFeedback- och QueryContinueDrag-händelser. Dessa händelser har standardhanterare som används om du inte markerar händelserna som hanterade. Du ignorerar vanligtvis dessa händelser om du inte har ett specifikt behov av att ändra deras standardbeteende.

Händelsen GiveFeedback aktiveras kontinuerligt när dragkällan dras. Standardhanteraren för den här händelsen kontrollerar om dragkällan är över ett giltigt släppmål. I så fall kontrollerar den de tillåtna effekterna av släppmålet. Därefter ger den feedback till den slutliga användaren om de tillåtna drag-och-släpp-effekterna. Detta görs vanligtvis genom att ändra musmarkören till en inte-släpp, kopiera- eller flytta-markör. Du bör bara hantera den här händelsen om du behöver använda anpassade markörer för att ge feedback till användaren. Om du behandlar den här händelsen, måste du markera den som behandlad så att standardhanteraren inte åsidosätter din hanterare.

Händelsen QueryContinueDrag aktiveras kontinuerligt när dragkällan dras. Du kan hantera den här händelsen för att avgöra vilken åtgärd som avslutar dra och släpp-åtgärden baserat på tillståndet för ESC-, SKIFT-, CTRL- och ALT-tangenterna samt musknapparnas tillstånd. Standardhanteraren för den här händelsen avbryter dra och släpp-åtgärden om ESC-tangenten trycks ned och släpper data om musknappen släpps.

Försiktighet

Dessa händelser aktiveras kontinuerligt under dra och släpp-åtgärden. Därför bör du undvika resursintensiva uppgifter i händelsehanterarna. Använd till exempel en cachelagrad markör i stället för att skapa en ny markör varje gång GiveFeedback händelsen aktiveras.

Aktivera ett element som ett släppmål

Ett objekt som är ett släppmål ansvarar för:

  • Specificera att det är ett giltigt släppmål.

  • Svarar på dragkällan när den dras över målet.

  • Kontrollera att de överförda data är i ett format som de kan ta emot.

  • Bearbeta borttagna data.

Om du vill ange att ett element är ett släppmål anger du dess egenskap AllowDrop till true. Händelserna för släppmål aktiveras sedan på elementet så att du kan hantera dem.

När ett släppmål utvärderas utförs ett träfftest för att identifiera om markören är över elementets visuella representation. Vissa kontroller, till exempel Canvas, har inget visuellt objekt och kan inte användas som släppmål om inte ett visuellt objekt läggs till. Ange egenskapen Canvas.Background till valfri färg för att skapa ett visuellt objekt som fyller Canvas med färg. Om du vill hålla Canvas transparent men aktivera det som ett släppmål anger du egenskapen Background till Transparent.

Under en dra och släpp-åtgärd sker följande sekvens av händelser på släppmålet:

  1. DragEnter

  2. DragOver

  3. DragLeave eller Drop

Den DragEnter händelsen inträffar när data dras till släppmålets gräns. Du hanterar vanligtvis den här händelsen för att tillhandahålla en förhandsgranskning av effekterna av dra och släpp-åtgärden, om det är lämpligt för ditt program. Ange inte egenskapen DragEventArgs.Effects i händelsen DragEnter eftersom den skrivs över i händelsen DragOver.

Följande exempel visar DragEnter-händelsehanteraren för ett Ellipse-element. Den här koden förhandsgranskar effekterna av drag-och-släpp-operationen genom att spara den aktuella Fill penseln. Den använder sedan metoden GetDataPresent för att kontrollera om DataObject som dras över ellipsen innehåller strängdata som kan konverteras till en Brush. I så fall extraheras data med hjälp av metoden GetData. Den konverteras sedan till en Brush och tillämpas på ellipsen. Ändringen återställs i händelsehanteraren för DragLeave. Om data inte kan konverteras till en Brushutförs ingen åtgärd.

private Brush _previousFill = null;
private void ellipse_DragEnter(object sender, DragEventArgs e)
{
    Ellipse ellipse = sender as Ellipse;
    if (ellipse != null)
    {
        // Save the current Fill brush so that you can revert back to this value in DragLeave.
        _previousFill = ellipse.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);
                ellipse.Fill = newFill;
            }
        }
    }
}
Private _previousFill As Brush = Nothing
Private Sub Ellipse_DragEnter(ByVal sender As System.Object, ByVal e As System.Windows.DragEventArgs)
    Dim ellipse = TryCast(sender, Ellipse)
    If ellipse IsNot Nothing Then
        ' Save the current Fill brush so that you can revert back to this value in DragLeave.
        _previousFill = ellipse.Fill

        ' If the DataObject contains string data, extract it.
        If e.Data.GetDataPresent(DataFormats.StringFormat) Then
            Dim dataString = 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 = CType(converter.ConvertFromString(dataString), Brush)
                ellipse.Fill = newFill
            End If
        End If
    End If
End Sub

Den DragOver händelsen inträffar kontinuerligt medan data dras över släppmålet. Den här händelsen kopplas ihop med GiveFeedback-händelsen på dragkällan. I DragOver händelsehanteraren använder du vanligtvis metoderna GetDataPresent och GetData för att kontrollera om de överförda data är i ett format som släppmålet kan bearbeta. Du kan också kontrollera om några modifierarnycklar trycks in, vilket vanligtvis anger om användaren avser en flytt- eller kopieringsåtgärd. När dessa kontroller har utförts anger du egenskapen DragEventArgs.Effects för att meddela dragkällan vilken effekt det kommer att få att släppa data. Dra-källan tar emot den här informationen i GiveFeedback händelseargument och kan ange en lämplig markör för att ge återkoppling till användaren.

Följande exempel visar DragOver-händelsehanteraren för ett Ellipse-element. Den här koden kontrollerar om DataObject som dras över ellipsen innehåller strängdata som kan konverteras till en Brush. Om så är fallet, sätter den DragEventArgs.Effects-egenskapen till Copy. Detta anger för dragkällan att data kan kopieras till ellipsen. Om data inte kan konverteras till en Brushanges egenskapen DragEventArgs.Effects till None. Detta anger för dragkällan att ellipsen inte är ett giltigt släppmål för data.

private void ellipse_DragOver(object sender, DragEventArgs 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.
        BrushConverter converter = new BrushConverter();
        if (converter.IsValid(dataString))
        {
            e.Effects = DragDropEffects.Copy | DragDropEffects.Move;
        }
    }
}
Private Sub Ellipse_DragOver(ByVal sender As System.Object, ByVal e As System.Windows.DragEventArgs)
    e.Effects = DragDropEffects.None

    ' If the DataObject contains string data, extract it.
    If e.Data.GetDataPresent(DataFormats.StringFormat) Then
        Dim dataString = 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
            e.Effects = DragDropEffects.Copy Or DragDropEffects.Move
        End If
    End If
End Sub

DragLeave-händelsen inträffar när data dras utanför målets gräns utan att släppas. Du hanterar den här händelsen för att återställa allt du gjorde i händelsehanteraren för DragEnter.

Följande exempel visar DragLeave-händelsehanteraren för ett Ellipse-element. Den här koden ångrar förhandsgranskningen som utförs i händelsehanteraren för DragEnter genom att tillämpa den sparade Brush på ellipsen.

private void ellipse_DragLeave(object sender, DragEventArgs e)
{
    Ellipse ellipse = sender as Ellipse;
    if (ellipse != null)
    {
        ellipse.Fill = _previousFill;
    }
}
Private Sub Ellipse_DragLeave(ByVal sender As System.Object, ByVal e As System.Windows.DragEventArgs)
    Dim ellipse = TryCast(sender, Ellipse)
    If ellipse IsNot Nothing Then
        ellipse.Fill = _previousFill
    End If
End Sub

Den Drop händelsen inträffar när data släpps över släppmålet. Detta inträffar som standard när musknappen släpps. I Drop händelsehanteraren använder du metoden GetData för att extrahera överförda data från DataObject och utföra databearbetning som programmet kräver. Händelsen Drop avslutar dra och släpp-åtgärden.

Följande exempel visar Drop-händelsehanteraren för ett Ellipse-element. Den här koden tillämpar effekterna av dra och släpp-åtgärden och liknar koden i DragEnter händelsehanteraren. Den kontrollerar om DataObject som dras över ellipsen innehåller strängdata som kan konverteras till en Brush. I så fall tillämpas Brush på ellipsen. Om data inte kan konverteras till en Brushutförs ingen åtgärd.

private void ellipse_Drop(object sender, DragEventArgs e)
{
    Ellipse ellipse = sender as Ellipse;
    if (ellipse != null)
    {
        // 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);
                ellipse.Fill = newFill;
            }
        }
    }
}
Private Sub Ellipse_Drop(ByVal sender As System.Object, ByVal e As System.Windows.DragEventArgs)
    Dim ellipse = TryCast(sender, Ellipse)
    If ellipse IsNot Nothing Then

        ' If the DataObject contains string data, extract it.
        If e.Data.GetDataPresent(DataFormats.StringFormat) Then
            Dim dataString = 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 = CType(converter.ConvertFromString(dataString), Brush)
                ellipse.Fill = newFill
            End If
        End If
    End If
End Sub

Se även