Table of Contents
Drag and Drop

Overview

EO.Wpf ListBox supports drag and drop inside the same ListBox control, between different ListBox controls, or between an EO.Wpf ListBox and an EO.Wpf.TreeView control. The control where the drag and drop originates is usually termed as "source", where the control on which user drops the item is usually termed as "target". This topic describes various scenarios where the "source" is:

You can also drag from an EO.Wpf ListBox to an EO.Wpf TreeView (with the ListBox being the "source" and the TreeView being the "target"). The steps are similar but they are discussed here.

Drag Source Is The Same ListBox Control

To allow drag drop inside the same ListBox control, simply set the ListBox's AllowDragItem and AllowDropItem to true. The following code demonstrates this features:

XAML
<Window x:Class="Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:eo="http://schemas.essentialobjects.com/wpf/"
        Title="MainWindow" Height="250" Width="350">
    <StackPanel>
        <eo:ListBox Width="200" HorizontalAlignment="Left" AllowDragItem="True" AllowDropItem="True">
            <eo:ListBoxItem>Item 1</eo:ListBoxItem>
            <eo:ListBoxItem>Item 2</eo:ListBoxItem>
            <eo:ListBoxItem>Item 3</eo:ListBoxItem>
            <eo:ListBoxItem>Item 4</eo:ListBoxItem>
            <eo:ListBoxItem>Item 5</eo:ListBoxItem>
        </eo:ListBox>
    </StackPanel>
</Window>

The following image demonstrates dragging "Item 1" in between "Item 3" and "Item 4". A line is highlighted between the two target items to indicate the drop location.

The above sample uses ListBoxItem statically declared in the XAML file. In this case when user drags and drops the item, the corresponding ListBoxItem element is moved (it can not be copied). In case the ListBoxItem is populated from a data source, the underlying data source is modified. For example, if the underlying data source is an ObservableCollection object, then when a ListBoxItem is being moved to a different location, the corresponding element in the ObservableCollection will be moved. In order for such modification to succeed, the data source:

  • Must not be readonly. For example, if the data source is a string array, then it can not delete an item. In that case the original item will not be moved;
  • Must support change notifications. When the underlying collection is changed, the ListBox must be notified so that it can updates its UI accordingly;

Because of these two reasons, it is recommended that you use ObservableCollection as the data source if you intend to enable drag and drop.

The default behavior for drag and drop an item is to move the item. You can enable item copy by setting ListBox.AllowDragCopy or ListBoxItem.AllowDragCopy to true. When this property is set to true, user can hold down the control key while drag and drop to copy an item. Note item copy can only be performed if the items are populated from a data source. A ListBoxItem declared directly through XAML or created with code cannot be copied. Alternatively, you can use a fixed sized data source, such as a string array. When a fixed sized data source is used, the item will always be copied since it can not be deleted from the original data source.

Drag Source Is Another ListBox Control

Drag and drop between two ListBox controls are very much identical to drag and drop within the same ListBox. You must set the source's AllowDragItem and the target item's AllowDropItem to true. The following code has two ListBox controls and both ListBox has AllowDragItem and AllowDropItem set to true.

XAML
<Window x:Class="Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:eo="http://schemas.essentialobjects.com/wpf/"
        Title="MainWindow" Height="250" Width="350">
    <StackPanel>
        <eo:ListBox Width="200" HorizontalAlignment="Left" AllowDragItem="True" AllowDropItem="True">
            <eo:ListBoxItem>Item A1</eo:ListBoxItem>
            <eo:ListBoxItem>Item A2</eo:ListBoxItem>
            <eo:ListBoxItem>Item A3</eo:ListBoxItem>
            <eo:ListBoxItem>Item A4</eo:ListBoxItem>
            <eo:ListBoxItem>Item A5</eo:ListBoxItem>
        </eo:ListBox>
        <eo:ListBox Width="200" HorizontalAlignment="Left" AllowDragItem="True" AllowDropItem="True">
            <eo:ListBoxItem>Item B1</eo:ListBoxItem>
            <eo:ListBoxItem>Item B2</eo:ListBoxItem>
            <eo:ListBoxItem>Item B3</eo:ListBoxItem>
            <eo:ListBoxItem>Item B4</eo:ListBoxItem>
            <eo:ListBoxItem>Item B5</eo:ListBoxItem>
        </eo:ListBox>
    </StackPanel>
</Window>

The following image demonstrates item "Item B1" (an item from the second ListBox) is being dragged in between two items in the first ListBox: "Item A2" and "Item A3":

Drag Source Is A TreeView Control

EO.Wpf ListBox and EO.Wpf TreeView uses the same drag and drop mechanism. So it is possible to drag an item from a TreeView into a ListBox. However since it usually does not make sense to directly "move" a TreeViewItem into a ListBox, it often requires the source TreeView to be populated from an ItemsSource. In this case, when a TreeViewItem is dragged into a ListBox, the data associated to the TreeViewItem is used to create a new ListBoxItem in the ListBox. The following code demonstrated this feature:

<Window x:Class="Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:eo="http://schemas.essentialobjects.com/wpf/"
        Title="MainWindow" Height="250" Width="450">
    <Grid HorizontalAlignment="Left">
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <TextBlock Margin="2">Celebrities:</TextBlock>
        <eo:TreeView x:Name="TreeView1" Width="200" Height="200" HorizontalAlignment="Left" Margin="2" Grid.Row="1" AllowDragItem="True" ItemBeginDrag="TreeView1_ItemBeginDrag">
            <eo:TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Path=Celebrities}">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition></ColumnDefinition>
                            <ColumnDefinition></ColumnDefinition>
                        </Grid.ColumnDefinitions>
                        <eo:Bitmap Grid.Column="0" Source="{Binding Image}" Margin="2"></eo:Bitmap>
                        <TextBlock Grid.Column="1" Text="{Binding Name}" VerticalAlignment="Center" Margin="5"></TextBlock>
                    </Grid>
                    <HierarchicalDataTemplate.ItemTemplate>
                        <DataTemplate>
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition></ColumnDefinition>
                                    <ColumnDefinition></ColumnDefinition>
                                </Grid.ColumnDefinitions>
                                <eo:Bitmap Grid.Column="0" Source="{Binding Image}" Margin="2"></eo:Bitmap>
                                <TextBlock Grid.Column="1" Text="{Binding Name}" VerticalAlignment="Center" Margin="5"></TextBlock>
                            </Grid>
                        </DataTemplate>
                    </HierarchicalDataTemplate.ItemTemplate>
                </HierarchicalDataTemplate>
            </eo:TreeView.ItemTemplate>
        </eo:TreeView>
        <TextBlock Margin="2" Grid.Column="1">My Favorites:</TextBlock>
        <eo:ListBox Width="200" Height="200" HorizontalAlignment="Left" 
                AllowDropItem="True" Margin="2" Grid.Row="1" Grid.Column="1">
            <eo:ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition></ColumnDefinition>
                            <ColumnDefinition></ColumnDefinition>
                        </Grid.ColumnDefinitions>
                        <eo:Bitmap Grid.Column="0" Source="{Binding Image}" Margin="2"></eo:Bitmap>
                        <TextBlock Grid.Column="1" Text="{Binding Name}" VerticalAlignment="Center" Margin="5"></TextBlock>
                    </Grid>
                </DataTemplate>
            </eo:ListBox.ItemTemplate>
        </eo:ListBox>
    </Grid>
</Window>

The following screenshot demonstrates the result: