Slepen en neerzetten

Slepen en neerzetten is een intuïtieve manier om gegevens over te dragen binnen een toepassing of tussen toepassingen op het Windows bureaublad. Met slepen en neerzetten kan de gebruiker gegevens overbrengen tussen toepassingen of binnen een toepassing met behulp van een standaardbeweging (met de vinger ingedrukt houden en verschuiven of klikken en verschuiven met een muis of stylus).

Belangrijke API's: eigenschap CanDrag, eigenschap AllowDrop

De sleepbron, de toepassing of het gebied waar de sleepbeweging wordt geactiveerd, biedt de gegevens die moeten worden overgedragen door een gegevenspakketobject te vullen. Dit object kan standaard gegevensformaten bevatten, waaronder tekst, RTF, HTML, bitmaps, opslagitems of aangepaste gegevensformaten. De bron geeft ook het type bewerkingen aan dat wordt ondersteund: kopiëren, verplaatsen of koppelen. Wanneer de aanwijzer wordt vrijgegeven, vindt de drop plaats. De doellocatie, die de toepassing of het gebied onder de aanwijzer is, verwerkt het gegevenspakket en retourneert het type bewerking dat het heeft uitgevoerd.

Tijdens slepen en neerzetten biedt de gebruikersinterface voor slepen een visuele indicatie van het type slepen-en-neerzetten dat plaatsvindt. Deze visuele feedback wordt aanvankelijk door de bron verstrekt, maar kan door de doelobjecten worden gewijzigd wanneer de aanwijzer eroverheen beweegt.

Met slepen en neerzetten kan gegevens worden overgedragen tussen of binnen elk type toepassing, waaronder klassieke Windows-apps, hoewel dit artikel is gericht op de XAML-API voor moderne slepen en neerzetten. Zodra de app is geïmplementeerd, werkt slepen en neerzetten naadloos in alle richtingen, waaronder app-naar-app, app-naar-desktop en bureaublad-naar-app.

Hier volgt een overzicht van wat u moet doen om slepen en neerzetten in uw app in te schakelen:

  1. Schakel slepen op een element in door de eigenschap CanDrag in te stellen op juist.
  2. Bouw het gegevenspakket. Het systeem verwerkt afbeeldingen en tekst automatisch, maar voor andere inhoud moet u de gebeurtenissen DragStarting en DropCompleted afhandelen en deze gebruiken om uw eigen gegevenspakket te maken.
  3. Schakel neerzetten in door de eigenschap AllowDrop in te stellen op true op alle elementen die verwijderde inhoud kunnen ontvangen.
  4. Behanteer de DragOver gebeurtenis om het systeem te informeren welk type sleepbewerkingen het element kan ontvangen.
  5. De drop gebeurtenis verwerken om de verwijderde inhoud te ontvangen.

Slepen inschakelen

Als u slepen op een element wilt inschakelen, stelt u de CanDrag eigenschap in op true. Dit maakt het element, evenals de elementen die het bevat in het geval van collecties zoals ListView, sleepbaar.

Wees specifiek over wat er kan worden gesleept. Gebruikers willen niet alles in uw app slepen, alleen bepaalde items, zoals afbeeldingen of tekst.

U kunt CanDrag als volgt instellen.

<Image x:Name="Image" CanDrag="True" Margin="10,292,10,0" Height="338"/>

U hoeft geen ander werk te doen om slepen toe te staan, tenzij u de gebruikersinterface wilt aanpassen (die verderop in dit artikel wordt besproken). Voor het verwijderen zijn nog enkele stappen vereist.

Een gegevenspakket maken

In de meeste gevallen maakt het systeem een gegevenspakket voor u. Het systeem verwerkt het volgende automatisch:

  • Afbeeldingen
  • Tekst

Voor andere inhoud moet u de DragStarting-gebeurtenissen en DropCompleted-gebeurtenissen afhandelen en deze gebruiken om je eigen DataPackagete maken.

Opmerking

De gebeurtenis DragStarting die hier wordt beschreven, maakt deel uit van UIElement en is de juiste gebeurtenis voor het maken van een aangepaste DataPackagegebeurtenis. Dit verschilt van de gebeurtenis DragStarted van besturingselementen van het type Thumb, die wordt gebruikt voor slepen in schuifregelaarstijl in plaats van voor gegevensoverdracht.

De DragStarting-gebeurtenis afhandelen

De dragStarting-gebeurtenis wordt geactiveerd wanneer het systeem een sleepbewerking start op een element met CanDrag="True". In de gebeurtenis-handler gebruikt u dragStartingEventArgs om de eigenschap Data (een DataPackage) te vullen met de inhoud die u wilt overdragen en stelt u De RequestedOperation in om aan te geven of de bewerking een kopie, verplaatsing of koppeling is.

Stel eerst het XAML-element in met zowel een DragStarting- als een DropCompleted-gebeurtenisafhandelaar:

<TextBlock x:Name="DraggableText" CanDrag="True"
           DragStarting="DraggableText_DragStarting"
           DropCompleted="DraggableText_DropCompleted"
           Text="Drag this text to another location"/>

Voer vervolgens in de code-behind de DragStarting-gebeurtenis uit om het gegevenspakket te vullen:

private void DraggableText_DragStarting(UIElement sender, DragStartingEventArgs args)
{
    // Add the text content to the data package
    args.Data.SetText(((TextBlock)sender).Text);

    // Indicate that both Copy and Move are acceptable
    args.Data.RequestedOperation = DataPackageOperation.Copy | DataPackageOperation.Move;
}

Als u asynchroon werk moet uitvoeren tijdens het samenstellen van het gegevenspakket (bijvoorbeeld het lezen van een bestand), gebruikt u de Methode GetDeferral om de gebeurtenis actief te houden totdat het werk is voltooid:

private async void DraggableText_DragStarting(UIElement sender, DragStartingEventArgs args)
{
    var deferral = args.GetDeferral();
    try
    {
        // Perform async work here, for example loading file content
        string content = await LoadCustomTextAsync();
        args.Data.SetText(content);
        args.Data.RequestedOperation = DataPackageOperation.Copy;
    }
    finally
    {
        deferral.Complete();
    }
}

De DropCompleted-gebeurtenis afhandelen

De gebeurtenis DropCompleted wordt geactiveerd op de sleepbron nadat de sleep-en-neerzetbewerking is voltooid, ongeacht of het item succesvol is neergezet of de sleepbewerking is geannuleerd. Gebruik de eigenschap DropCompletedEventArgs.DropResult om het resultaat te bepalen en actie te ondernemen, zoals het verwijderen van het bronitem als een verplaatsing is uitgevoerd:

private void DraggableText_DropCompleted(UIElement sender, DropCompletedEventArgs args)
{
    if (args.DropResult == DataPackageOperation.Move)
    {
        // The target accepted the data as a Move, so clear the source
        ((TextBlock)sender).Text = string.Empty;
    }
}

Zie het XAML-voorbeeld van slepen en neerzetten op GitHub voor een volledig werkend voorbeeld van aangepaste slepen en neerzetten met een gegevenspakket.

Verwijderen inschakelen

In de volgende markeringen ziet u hoe de eigenschap AllowDrop kan worden gebruikt om op te geven dat een gebied van de app een geldig drop-doel is voor een gesleept item (het opgegeven gebied mag geen null-achtergrond hebben, moet de aanwijzerinvoer kunnen ontvangen en het item kan nergens anders dan het opgegeven gebied worden verwijderd).

Opmerking

Normaal gesproken heeft een UI-element standaard een null-achtergrond. Als u wilt dat gebruikers ergens in uw app een item kunnen neerzetten, kan de app-achtergrond niet null zijn (instellen Background="Transparent" als de achtergrond niet zichtbaar mag zijn).

<Grid AllowDrop="True" DragOver="Grid_DragOver" Drop="Grid_Drop"
      Background="LightBlue" Margin="10,10,10,353">
    <TextBlock>Drop anywhere in the blue area</TextBlock>
</Grid>

De DragOver-gebeurtenis afhandelen

De DragOver gebeurtenis wordt geactiveerd wanneer een gebruiker een item boven uw app heeft gesleept, maar nog niet heeft neergezet. In deze handler moet u opgeven welk type bewerkingen uw app ondersteunt met behulp van de eigenschap AcceptedOperation . Kopiëren is het meest gebruikelijk.

private void Grid_DragOver(object sender, DragEventArgs e)
{
    e.AcceptedOperation = DataPackageOperation.Copy;
}

De drop-gebeurtenis verwerken

De gebeurtenis Drop vindt plaats wanneer de gebruiker items in een geldige dropzone loslaat. Verwerk ze met behulp van de eigenschap DataView .

Voor het gemak in het onderstaande voorbeeld gaan we ervan uit dat de gebruiker één foto heeft verwijderd en deze rechtstreeks opent. In werkelijkheid kunnen gebruikers meerdere items met verschillende indelingen tegelijk verwijderen. Uw app moet deze mogelijkheid afhandelen door te controleren welke typen bestanden zijn verwijderd en hoeveel er zijn en om dienovereenkomstig te verwerken. U moet ook overwegen de gebruiker op de hoogte te stellen als deze iets probeert te doen wat uw app niet ondersteunt.

private async void Grid_Drop(object sender, DragEventArgs e)
{
    if (e.DataView.Contains(StandardDataFormats.StorageItems))
    {
        var items = await e.DataView.GetStorageItemsAsync();
        if (items.Count > 0)
        {
            var storageFile = items[0] as StorageFile;
            var bitmapImage = new BitmapImage();
            bitmapImage.SetSource(await storageFile.OpenAsync(FileAccessMode.Read));
            // Set the image on the main page to the dropped image
            Image.Source = bitmapImage;
        }
    }
}

De gebruikersinterface aanpassen

Het systeem biedt een standaardgebruikersinterface voor slepen en neerzetten. U kunt er echter ook voor kiezen om verschillende onderdelen van de gebruikersinterface aan te passen door aangepaste bijschriften en glyphs in te stellen, of door ervoor te kiezen om helemaal geen gebruikersinterface weer te geven. Als u de gebruikersinterface wilt aanpassen, gebruikt u de eigenschap DragEventArgs.DragUIOverride .

private void Grid_DragOverCustomized(object sender, DragEventArgs e)
{
    e.AcceptedOperation = DataPackageOperation.Copy;
    e.DragUIOverride.Caption = "Custom text here"; // Sets custom UI text
    // Sets a custom glyph
    e.DragUIOverride.SetContentFromBitmapImage(
        new BitmapImage(
            new Uri("ms-appx:///Assets/CustomImage.png", UriKind.RelativeOrAbsolute)));
    e.DragUIOverride.IsCaptionVisible = true; // Sets if the caption is visible
    e.DragUIOverride.IsContentVisible = true; // Sets if the dragged content is visible
    e.DragUIOverride.IsGlyphVisible = true; // Sets if the glyph is visibile
}

Een snelmenu openen op een item dat u met aanraken kunt slepen

Wanneer u aanraking gebruikt, deelt het slepen van een UIElement en het openen van het contextmenu vergelijkbare aanraakgebaren; beide starten met drukken en vasthouden. Hier ziet u hoe het systeem onderscheid maakt tussen de twee acties voor elementen in uw app die beide ondersteunen:

  • Als een gebruiker een item ingedrukt houdt en het binnen 500 milliseconden sleept, wordt het item gesleept en wordt het contextmenu niet weergegeven.
  • Als de gebruiker ingedrukt houdt maar niet sleept gedurende 500 milliseconden, wordt het contextmenu geopend.
  • Nadat het contextmenu is geopend, wordt het contextmenu gesloten als de gebruiker het item probeert te slepen (zonder zijn vinger op te tillen) en wordt het slepen gestart.

Een item in een ListView of GridView aanwijzen als map

U kunt een ListViewItem of GridViewItem opgeven als map. Dit is met name handig voor TreeView- en Verkenner-scenario's. Hiervoor stelt u de eigenschap AllowDrop expliciet in op True voor dat item.

Het systeem toont automatisch de juiste animaties voor het neerzetten in een map versus een item zonder map. Uw app-code moet de gebeurtenis Neerzetten blijven verwerken op het mapitem (en op het item zonder map) om de gegevensbron bij te werken en het verwijderde item toe te voegen aan de doelmap.

Volgorde van slepen en neerzetten in ListViews inschakelen

ListViews bieden ondersteuning voor op slepen gebaseerde hervolgorde, met behulp van een API die vergelijkbaar is met de CanDrop API die in dit artikel wordt beschreven. U voegt minimaal de eigenschappen AllowDrop en CanReorderItems toe.

Zie ListViewBase.CanReorderItems voor meer informatie.

Implementatie van aangepast slepen en neerzetten

De UIElement klasse neemt het grootste deel van de implementatie van slepen en neerzetten voor je op zich. Maar als u wilt, kunt u uw eigen versie implementeren met behulp van de onderstaande API's.

Functionaliteit Windows App SDK
Microsoft.UI.Input.DragDrop-naamruimte
DragPrimitive DragOperation
Een gegevenspakket maken DataPackage
Draag slepen over aan de shell DragOperation.StartAsync
Drop van de shell ontvangen DragDropManager.TargetRequested
IDropOperationTarget

Zie ook