I’ve been struggling using the gong-wpf-dragdrop framework in combination with a Canvas as drop target. There wasn’t very much information available about using the framework with controls other than the ListBox/ListView and TreeView types, so I decided to do a little of trial and error and came up with the following solution.
Instead of using the framework properties directly on a Canvas control, I still use them on ListBox:
<ListBox
ItemsSource="{Binding Path=ItemsSource}"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.DropHandler="{Binding}"
dd:DragDrop.DragHandler="{Binding}" />
Why use the ListBox when my goal is to use the Canvas as the drop container? It’s simple: when trying to use the DragDrop properties on a Canvas, the framework throws a NullReferenceException when the drag enters the Canvas. The solution to this problem is this: use a Canvas as the ListBox ItemsPanelTemplate by styling the ListBox.
<!-- ListBox style -->
<Style
TargetType="{x:Type ListBox}">
<Setter
Property="ItemsControl.ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter
Property="ScrollViewer.HorizontalScrollBarVisibility"
Value="Disabled" />
</Style>
Now we realized a Canvas on which we can drop items using the gong-wpf-dragdrop framework. The only problem left is the positioning of the items, because they’re being placed on top of each other. To tackle this I came up with the idea to store the position of the item in the ViewModel that it represents. Of course these X and Y values are view-specific and thus must not be stored in the Model. In my opinion they can be stored in the ViewModel because that’s where the View and the Model come together.
Useful links: