Using Drag-and-Drop with the LibraryBar and LibraryStack Controls

The LibraryBar and LibraryStack controls that are included in the Microsoft Surface Toolkit for Windows Touch Beta have built-in support for drag-and-drop operations. By combining these controls in your application, you can easily enable users to take items (such as images) from one control and place them into another control.

The following illustration shows a LibraryBar control that is populated with images. In this example, users can drag images from the LibraryBar control and drop them on a LibraryStack control.

Drag-and-drop - Drag image from LibraryBar to

When a user drags an item out of the LibraryBar control, the image is not removed. Instead, it is placed into an inactive state (which is represented by making the item dimmer than normal in the LibraryBar control).

The item is removed from the LibraryBar control if the item itself is a visual and no ContentTemplate is set.

When an item is dropped onto a LibraryStack control, the item is added to the Items collection of the control. If the ItemsSource property is set, the item is also added to the collection that is associated with that property. The following illustration shows a LibraryStack control that has had two items dropped on it.

Example of the LibraryStack and LibraryBar

The following code example shows the main Grid control for the SurfaceWindow control of this sample application.

        <RowDefinition />
        <RowDefinition />
        Grid.Row="0" Grid.Column="0"
        Height="250" Width="860">
                <Image Source="{Binding}"/>

        Grid.Row="1" Grid.Column="0"
        Height="350" Width="350">
                <Image Source="{Binding}"/>


During initialization, the ItemsSource property of the LibraryBar control is set to a collection of sample images.

protected override void OnInitialized(EventArgs e)

    // Query the registry to find out where the sample photos are stored.
    const string shellKey =
        @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\Shell Folders";

    string imagesPath =
        (string)Microsoft.Win32.Registry.GetValue(shellKey, "CommonPictures", null) + @"\Sample Pictures";

        // Get the list of files.
        string[] files = System.IO.Directory.GetFiles(imagesPath, "*.jpg");

        // Create an ObservableCollection from the file names.
        // LibraryBar.ItemsSource should implement INotifyCollectionChanged
        // in order for the built-in drag-and-drop capability to work properly.
        ObservableCollection<string> items = new ObservableCollection<string>(files);

        // Set the ItemsSource property.
        MainLibraryBar.ItemsSource = items;
    catch (System.IO.DirectoryNotFoundException)
        // Handle exception as needed.

Changing the Default Drag-and-Drop Cursor

By default, the drag cursor is a simple representation of the content that is being dragged. You can customize the drag cursor by defining a custom Style object, and setting the Microsoft.Surface.Presentation.Controls.LibraryBar.DragCursorStyle and the Microsoft.Surface.Presentation.Controls.LibraryStack.DragCursorStyle properties to an instance of the custom style.

MainLibraryBar.DragCursorStyle = (Style)Resources["LibraryBarDragCursor"];
MainLibraryStack.DragCursorStyle = (Style)Resources["LibraryStackDragCursor"];

The following illustration shows a user dragging an item from a LibraryBar control that has had its Microsoft.Surface.Presentation.Controls.LibraryBar.DragCursorStyle property set to an instance of a custom Style object. The XAML for the custom style (shown in the next section) superimposes the two ellipses over the dragged image, and scales the cursor to be larger than the default.

Drag-and-drop - custom cursor

The following code example shows the XAML for the Resources section of the SurfaceWindow control of this sample application.

    <!-- The scale transforms for the drag cursors. -->
    <ScaleTransform x:Key="LibraryBarDragCursorScale" ScaleX="1.65" ScaleY="1.65"/>
    <ScaleTransform x:Key="LibraryStackDragCursorScale" ScaleX="1.0" ScaleY="1.0"/>

    <!-- The custom style for the LibraryBarItem drag cursor. -->
    <Style x:Key="LibraryBarDragCursor" TargetType="ContentControl">

        <Setter Property="RenderTransform" Value="{StaticResource LibraryBarDragCursorScale}"/>

        <Setter Property="Template">
                <ControlTemplate TargetType="ContentControl">
                                    <Image Source="{Binding}"/>

                            Width="{TemplateBinding Width}" 
                            Height="{TemplateBinding Height}" 
                            Opacity="0.5" Fill="White"/>

                        <Ellipse Width="12" Height="12" Opacity="0.50" Fill="Red"/>

    <!-- The custom style for the LibraryStackItem drag cursor. -->
    <!-- It is the same as the style for LibraryBarItem except for the scale.-->
        BasedOn="{StaticResource LibraryBarDragCursor}">

        <Setter Property="RenderTransform" Value="{StaticResource LibraryStackDragCursorScale}"/>

Changing the Default Drag-and-Drop Behavior

By default, when a user drags an item from the LibraryBar control and drops it onto another control, the item remains in the LibraryBar control in an inactive (dimmed) state. You can change this behavior by attaching a PreviewDropEvent event handler to the target control.

SurfaceDragDrop.AddPreviewDropHandler(MainLibraryStack, OnPreviewDrop);

When a user drops the dragged item on the LibraryStack control, the attached event is raised. In the event handler, check to see if the DragSource property belongs to the source LibraryBar control. If it does, change the Effects property to DragDropEffects.Move so the item is removed from the source LibraryBar control.

private void OnPreviewDrop(object sender, SurfaceDragDropEventArgs e)
    if (MainLibraryBar.IsAncestorOf(e.Cursor.DragSource))
        e.Effects = DragDropEffects.Move;

To prevent users from dropping an item on the LibraryBar control that does not belong on it, attach an PreviewQueryTargetEvent event handler to the LibraryBar control.

SurfaceDragDrop.AddPreviewQueryTargetHandler(MainLibraryBar, OnPreviewQueryTarget);

When the attached event is raised, check to see if the Data property of the event arguments belongs to the LibraryBar control. If it does not belong, reject the item by setting the UseDefault property to false, the ProposedTarget property to null, and the Handled property to true.

private void OnPreviewQueryTarget(object sender, QueryTargetEventArgs e)
    LibraryBar bar = (LibraryBar)sender;
    if (!bar.Items.Contains(e.Cursor.Data))
        e.UseDefault = false;
        e.ProposedTarget = null;
        e.Handled = true;
If you combine these two techniques, after a user drags an item from the LibraryBar control to the LibraryStack control, the user cannot drag the item back to the LibraryBar control.

See Also

Community Additions