3
votes

I want to implement drag & drop for a extended-selection-mode WPF ListBox. So far, everything is working fine:

  1. I can initiate a drag operation for the selected items
  2. I can handle the drop operation on the target

I basically implemented it as written here - in short:

  1. Handle PreviewMouseLeftButtonDown to store current mouse position
  2. Handle MouseMove to initiate the drag operation if distance has been covered

Now my problem is: Usually, in the Explorer for example, I'd select the items I want to drag, then I release the mouse button and press it again to initiate the drag & drop operation. I guess that's how most users would do it. When I do the same thing in my application now, the selection changes to the item I press the mouse button on for the second time - the multi-selection is gone.

I googled a lot yesterday, but all the solutions I could find initiated the drag operation in PreviewMouseLeftButtonDown. That, however, does not allow me to check whether the mouse has been moved far enough to actually initiate a drag operation.

My question: Does anyone have a simple solution (not involving any third-party libraries) how I can change the sample linked above so that the multi-selection stays intact?

1

1 Answers

3
votes

The problem is that the selection-mode of ListBox or ListView are different with the one used for Explorer:

For ListBox with extended-selection-mode:

User can de-select item with just MouseDown;

while for Explorer:

User can not de-select item with just MouseDown, they can only do it until MouseUp.

So that's core reason behind why in Explorer, user can select an item, release Mouse, and then press it again to start the drag & drop.

In order to implement Explorer-like selection and drag&drop effect, you need to first differentiate if an item is selected when MouseDown, so when an item IsSelected you will defer it's selection change until MouseUp.

You can check this article for more ideas and here is a prototype for you to start with:

private void ListBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    if (VisualTreeHelper.GetParent(e.OriginalSource as UIElement) is ListBoxItem)
    {
        ListBoxItem item = (ListBoxItem)VisualTreeHelper.GetParent(e.OriginalSource as UIElement);
        if (item == null) return;
        if (item.IsSelected)
        {
            e.Handled = true;
        }
    }     
}