UWP: How to implement Drag and Drop functionality

One more new feature, which is available for Windows 10 developers, is Drag and Drop support. Starting with Windows 10 you can implement Drag and Drop functionality between UI parts of your application or use external sources/targets including Win 32 applications.

Let’s start with Drag operation. In order to show how Drag operation works, I simply added an image from the application package to the main page.

 <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
 <Image Source="Assets\drone.jpg" Name="image" CanDrag="True" DragStarting="Image_DragStarting" Margin="100" VerticalAlignment="Top" HorizontalAlignment="Left"></Image>
</Grid>

You can see two important attributes there that activate Drag operation: CanDrag and DragStarting. CanDrag attribute is just a flag which enables the feature for all UIElement controls but DragStaring attribute contains name for event handler. Thanks to this event handler you can define any content to drag. In my case I implemented the following handler:

 private async void Image_DragStarting(UIElement sender, DragStartingEventArgs args)
{
 List<IStorageItem> files = new List<IStorageItem>();
 StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/drone.jpg"));
 files.Add(file);
 
 args.DragUI.SetContentFromDataPackage();
 args.Data.RequestedOperation = DataPackageOperation.Copy;
 args.Data.SetStorageItems(files);
}

In this event handler I used StorageFile class in order to pass my image like a file and thanks to Data property of DragStartingEventArgs parameter I packaged the file to the object of DataPackage class. DataPackage class is very popular among different features in Universal Windows Platform and usually you need to pass it to the operation system and OS allows to select the target application. But in case of Drag functionality user selects the target directly. So, we just need to prepare the DataPackage and that’s all.

Additionally I used two important properties there: DragUI and RequestedOperation. Thanks to the RequestedOperation I can assign the right operation and user should not be able to select anything from system menu – just drag and drop. Thanks to DragUI I can apply the content which will be shown during Drag operation. If you don’t use DragUI property, user will see the same image with the same width and height like in your application. It’s not very cozy to drag a huge image especially if you don’t use RequestedOperation – the system menu will be behind the image. That’s why you can assign any other content using DragUI or use SetContentFromDataPackage method in order to ask API to prepare appropriate icon for you based on content in DataPackage. Just run the application and drag and drop the image to the file explorer – image will be copied to the selected folder.

Let’s see how to implement an opposite task – Drop functionality. I want to accept several images. So, I am going to use ListView in order to show my items.

 <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"AllowDrop="True" Drop="Grid_Drop" DragEnter="Grid_DragEnter">
<ListView Margin="50" Name="listView">
 <ListView.ItemTemplate>
 <DataTemplate>
 <Grid>
 <Image Source="{Binding Source}" Width="200" Margin="10"></Image>
 </Grid>
 </DataTemplate>
 </ListView.ItemTemplate>
</ListView>
</Grid> 

You can see that I am using AllowDrop to activate the Drop functionality, DragEnter – to setup allowed operations (Copy) and Drop – to get content from DataPackage and show it using ListView.

In order to create items source for images I created BitmapItem class:

 class BitmapItem
{
 public ImageSource Source { get; set; }
} 

In the next step I implemented DragEnter event handler in order to notify the system about supported operations.

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

Finally, I am using DataPackageView in order to get reference to the content. DataPackageView can contain anything but I want to work with files only, so I call GetStorageItemsAsync in order to get references to files there and use BitmapImage to prepare the image files for Image objects.

 private async void Grid_Drop(object sender, DragEventArgs e)
{
 var files=await e.DataView.GetStorageItemsAsync();
 List<BitmapItem> items = new List<BitmapItem>();
 foreach(StorageFile file in files)
 {
 try
 {
 BitmapImage bi = new BitmapImage();
 bi.SetSource(await file.OpenAsync(FileAccessMode.Read));
 items.Add(new BitmapItem() { Source = bi });
 }
 catch { }
 }
 listView.ItemsSource = items;
} 

I am too lazy, so I decided to avoid any checking – I simply use empty catch block if user passed non-image file(s).

That’s all. You can see that it’s easy to implement Drag and Drop functionality and you can make experiments with different content types there or implement the same functionality inside the same application (drag and drop content from one part of application to another).