Thursday, 11 September 2008

Demonstrate Drag and Drop from ListBox to ListBox in WPF

Still haven't be able to created the memory leak problem.

I have implemented simple drag and drop from one ListBox to another ListBox onto my memory leak test project. The power of WPF, all I did was create an adorner for visualising drag and drop, and remove/add object from/to the data binding sources.

By the way, no guarantee to be bug-free because implementing drag and drop logic was not my intention. I am trying to find out the memory leak problem!

Download

Anyway, let me note some key points:

1. A Canvas encapsulating the ListBoxes (in ShapeListCollectionControl.xaml)

<Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Name="TestCanvas"
DragOver="TestCanvas_DragOver">
    <ListBox Width="300" Margin="0,0,0,0" Name="TestListBox"
PreviewMouseLeftButtonDown="TestListBox_PreviewMouseLeftButtonDown"
AllowDrop="True" Drop="TestListBox_Drop"
GiveFeedback="TestListBox_GiveFeedback">
<ListBox.ItemTemplate>
<DataTemplate>
<main:ShapeListControl ListID="{Binding Path=ListID}"
HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Canvas>

Don't worry about the event handlers yet. Having a canvas as a wrapper allow you to add adorner to the canvas when you start dragging.

2. Start dragging - TestListBox_PreviewMouseLeftButtonDown (in ShapeListCollectionControl.xaml.cs)
Note that I didn't write the GetObjectDataFromPoint method, I didn't even find it. All I have done was made it into an extension method.

Anyway. So the PreviewMouseLeftButtonDown event handler does the following:

i. Find out what has been dragged
ii. Find out the object list
iii. Set the selected shape
iv. Create Adorner and add to the canvas
v. Remember the offset positions
vi. Start dragging

3. Dragging - TestCanvas_DragOver
Note that here I am dragging the adorner, NOT the actual control. And it is in the canvas, not the ListBox!

4. Dropping - TestCanvas_Drop
To drop the selected shape, find the ShapeList by drop position. In the data model, remove the shape from the list we drag from and add to the list we drop to. After that remove adorner and reset selection.

object data = TestListBox.GetObjectDataFromPoint(position);

if (!(data is ShapeList))
{
RemoveAdorner();
return;
}

ShapeList list = data as ShapeList;

// Change Data
if (Manager.FromList != null)
{
Shape s = Manager.SelectedShapeControl.Shape;
Manager.FromList.Remove(s);
list.Add(s);
}

No comments:

Post a Comment