Drag & Drop Service feature

June 15, 2021 ยท View on GitHub

:heavy_exclamation_mark: There is also a version of this document with code samples in C# :heavy_exclamation_mark:

In Windows Template Studio, the Drag & Drop feature is a service that basically is a wrapper over the standard UWP drag and drop functionality. This service simplify the required code to create drag and drop ready apps as well as follows the framework pattern used by your app.

While using Code-Behind framework, the events will be handled by using actions. When using frameworks based on MVVM pattern (MVVM Light, Caliburn.Micro or MVVM Basic) the events will be handled by using commands.

Following you find the actions, for code-behind framework, or commands, for MVVM based frameworks, which returns the different object types supported by drag and drop within UWP:

Command (MVVM pattern)Action (code-behind)Return Type
DropDataViewCommandDropDataViewActionDataPackageView
DropApplicationLinkCommandDropApplicationLinkActionUri
DropBitmapCommandDropBitmapActionRandomAccessStreamReference
DropHtmlCommandDropHtmlActionstring
DropRtfCommandDropRtfActionstring
DropStorageItemsCommandDropStorageItemsActionIReadOnlyList
DropTextCommandDropTextActionstring
DropWebLinkCommandDropWebLinkActionUri

The service maps the following events too:

EventCommand (MVVM pattern)Action (code-behind)Return Type
UIElement.DragEnterDragEnterCommandDragEnterActionDragDropData
UIElement.DragOverDragOverCommandDragOverActionDragDropData
UIElement.DragLeaveDragLeaveCommandDragLeaveActionDragDropData
ListViewBase.DragItemsStartingDragItemsStartingCommandDragItemsStartingActionDragDropStartingData
ListViewBase.DragItemsCompletedDragItemsCompletedCommandDragItemsCompletedActionDragDropCompletedData

The feature provides three configuration types as well to easily setup the Drag & Drop service:

  • DropConfiguration: Provides the drag and drop configuration properties for any element derived from UIElement.
  • ListViewDropConfiguration: Provides the drag and drop configuration properties for any element derived from ListViewBase.
  • VisualDropConfiguration: Provides the drag and drop configuration properties for visual customization.

How to use the service

To use the service, you need to follow these steps:

  1. Define your valid drag and drop areas: Use the elements AllowDrop and CanDrag properties to designate the elements of your app valid for dragging and dropping. (https://docs.microsoft.com/windows/uwp/design/input/drag-and-drop). In the ListView element you can use CanDragItems property.

  2. Include the service reference within the page by adding the required namespace: xmlns:dd="using:AppNameSpace.Services.DragAndDrop"

  3. Configure the service appropriately

  • For an UIElement:
<Grid>
    <dd:DragDropService.Configuration>
        <dd:DropConfiguration  />
    </dd:DragDropService.Configuration>
</Grid>
  • For a ListView:
<ListView>
    <dd:DragDropService.Configuration>
        <dd:ListViewDropConfiguration  />
    </dd:DragDropService.Configuration>
</ListView>
  • For visual customization:
<Grid>
    <dd:DragDropService.VisualConfiguration>
        <dd:VisualDropConfiguration  />
    </dd:DragDropService.VisualConfiguration>
</Grid>

In the following section you can find how to setup a basic configuration.

Drag and drop basic configuration

In this section you can find some code snippets representing how to setup a basic Drag and Drop service configuration for apps based on MVVM Basic or Code-Behind frameworks. For other MVVM pattern based frameworks, the definition is like MVVM Basic.

Scenario 1 : Configure a grid to allow drop one or more files

MVVM Basic

  • XAML Page
<Grid Background="{ThemeResource SystemControlPageBackgroundChromeLowBrush}"
    AllowDrop="True">
    <dd:DragDropService.Configuration>
        <dd:DropConfiguration
            DropStorageItemsCommand="{x:Bind ViewModel.GetStorageItemsCommand}" />
    </dd:DragDropService.Configuration>
</Grid>
  • ViewModel code
Imports System.Collections.Generic
Imports Windows.Storage
Imports System.Windows.Input

...

Private _getStorageItemsCommand As ICommand

Public Property GetStorageItemsCommand As ICommand
    Get
        Return If(_getStorageItemsCommand, (__InlineAssignHelper(_getStorageItemsCommand, New RelayCommand(Of IReadOnlyList(Of IStorageItem))(OnGetStorageItem))))
    End Get
End Property

Public Sub OnGetStorageItem(ByVal items As IReadOnlyList(Of IStorageItem))
    For Each item In items
        ' TODO WTS: Process storage item
    Next
End Sub

Code-Behind

  • XAML Page
<Grid Background="{ThemeResource SystemControlPageBackgroundChromeLowBrush}"
    AllowDrop="True">
    <dd:DragDropService.Configuration>
        <dd:DropConfiguration
            DropStorageItemsAction="{x:Bind GetStorageItem}"   />
    </dd:DragDropService.Configuration>
</Grid>
  • ViewModel code
Imports System.Collections.Generic
Imports Windows.Storage

...

Public Property GetStorageItem As Action(Of IReadOnlyList(Of IStorageItem))
    Get
        Return(Function(items) OnGetStorageItem(items))
    End Get
End Property

Public Sub OnGetStorageItem(ByVal items As IReadOnlyList(Of IStorageItem))
    For Each item In items
        ' TODO WTS: Process storage item
    Next
End Sub

Scenario 2: Drag and drop enabled ListView

We will configure a ListView to allow drag items from it and drop items to it. We will also include some customizations.

We will need a class to be used class model during the drag and drop operations, for example the CustomItem class:

Public Class CustomItem

    Public ReadOnly Property Id As Guid = Guid.NewGuid()

    Public Property FileName As String

    Public Property OriginalStorageItem As IStorageItem
End Class

MVVM Basic

  • XAML Page
<ListView
    AllowDrop="True"
    CanDragItems="True"
    ItemsSource="{x:Bind ViewModel.Items}">

    <dd:DragDropService.Configuration>
        <dd:ListViewDropConfiguration
            DropStorageItemsCommand="{x:Bind ViewModel.GetStorageItemsCommand}"
            DragItemsStartingCommand="{x:Bind ViewModel.DragItemStartingCommand}"
            DragItemsCompletedCommand="{x:Bind ViewModel.DragItemCompletedCommand}" />
    </dd:DragDropService.Configuration>

    <dd:DragDropService.VisualConfiguration>
        <dd:VisualDropConfiguration
            Caption="Custom text here"
            IsContentVisible="False"
            IsGlyphVisible="False"/>
    </dd:DragDropService.VisualConfiguration>
</ListView>
  • ViewModel code
Private _getStorageItemsCommand As ICommand

Private _dragItemStartingCommand As ICommand

Private _dragItemCompletedCommand As ICommand

Public Property GetStorageItemsCommand As ICommand
    Get
        Return If(_getStorageItemsCommand, (__InlineAssignHelper(_getStorageItemsCommand, New RelayCommand(Of IReadOnlyList(Of IStorageItem))(OnGetStorageItem))))
    End Get
End Property

Public Property DragItemStartingCommand As ICommand
    Get
        Return If(_dragItemStartingCommand, (__InlineAssignHelper(_dragItemStartingCommand, New RelayCommand(Of DragDropStartingData)(OnDragItemStarting))))
    End Get
End Property

Public Property DragItemCompletedCommand As ICommand
    Get
        Return If(_dragItemCompletedCommand, (__InlineAssignHelper(_dragItemCompletedCommand, New RelayCommand(Of DragDropCompletedData)(OnDragItemCompleted))))
    End Get
End Property

Public Property Items As ObservableCollection(Of CustomItem) = New ObservableCollection(Of CustomItem)()

Private Sub OnGetStorageItem(ByVal items As IReadOnlyList(Of IStorageItem))
    For Each item As StorageFile In items
        Items.Add(New CustomItem With {.FileName = item.Name, .OriginalStorageItem = item})
    Next
End Sub

Private Sub OnDragItemStarting(ByVal startingData As DragDropStartingData)
    Dim items = startingData.Items.Cast(Of CustomItem)().[Select](Function(i) i.OriginalStorageItem)
    startingData.Data.SetStorageItems(items)
    startingData.Data.RequestedOperation = DataPackageOperation.Copy
End Sub

Private Sub OnDragItemCompleted(ByVal completedData As DragDropCompletedData)
    If completedData.DropResult <> DataPackageOperation.None Then
        Dim draggedItems = completedData.Items.Cast(Of CustomItem)()
        For Each item In draggedItems
            Items.Remove(item)
        Next
    End If
End Sub

Code-Behind

  • XAML Page
<ListView x:Name="listview"
            AllowDrop="True"
            CanDragItems="True"
            ItemsSource="{x:Bind Items}">

    <dd:DragDropService.Configuration>
        <dd:ListViewDropConfiguration
            DropStorageItemsAction="{x:Bind GetStorageItems}"
            DragItemsStartingAction="{x:Bind DragItemStarting}"
            DragItemsCompletedAction="{x:Bind DragItemCompleted}" />
    </dd:DragDropService.Configuration>

    <dd:DragDropService.VisualConfiguration>
        <dd:VisualDropConfiguration
            Caption="Custom text here"
            IsContentVisible="False"
            IsGlyphVisible="False"/>
    </dd:DragDropService.VisualConfiguration>
</ListView>
  • ViewModel code
Public Property GetStorageItems As Action(Of IReadOnlyList(Of IStorageItem))
    Get
        Return Function(items) OnGetStorageItems(items)
    End Get
End Property

Public Property DragItemStarting As Action(Of DragDropStartingData)
    Get
        Return Function(startingData) OnDragItemStarting(startingData)
    End Get
End Property

Public Property DragItemCompleted As Action(Of DragDropCompletedData)
    Get
        Return Function(completedData) OnDragItemCompleted(completedData)
    End Get
End Property

Public Property Items As ObservableCollection(Of CustomItem) = New ObservableCollection(Of CustomItem)()

Private Sub OnGetStorageItems(ByVal items As IReadOnlyList(Of IStorageItem))
    For Each item As StorageFile In items
        Items.Add(New CustomItem With {.FileName = item.Name, .OriginalStorageItem = item})
    Next
End Sub

Private Sub OnDragItemStarting(ByVal startingData As DragDropStartingData)
    Dim items = startingData.Items.Cast(Of CustomItem)().[Select](Function(i) i.OriginalStorageItem)
    startingData.Data.SetStorageItems(items)
    startingData.Data.RequestedOperation = DataPackageOperation.Copy
End Sub

Private Sub OnDragItemCompleted(ByVal completedData As DragDropCompletedData)
    If completedData.DropResult <> DataPackageOperation.None Then
        Dim draggedItems = completedData.Items.Cast(Of CustomItem)()
        For Each item In draggedItems
            Items.Remove(item)
        Next
    End If
End Sub