For a project I'm working on I needed to create a treeview with drag/drop reordering. Before messing with the actual project, I subclassed treeview in a separate project and added handlers for the Drop, DragOver, MouseMove, and DragLeave events and implemented them as necessary. Drag and drop reordering works fine for the side project because I had it set up such that each TreeViewItem stores the item I am interested in in the Header property.
Here is some of the code:
void MultiSelectTreeView_Drop(object sender, System.Windows.DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(TreeViewItem)))
{
TreeViewItem sourceItem = (TreeViewItem)e.Data.GetData(typeof(TreeViewItem));
TreeViewItem targetItem = e.Source as TreeViewItem;
dynamic parent;
if (targetItem == null) //not dropped in the treeview
{
_isDragging = false;
return;
}
else if (targetItem.Parent is TreeViewItem) //drag must start from either a treeviewitem...
{
parent = targetItem.Parent as TreeViewItem;
}
else // ... or the root treeview
{
parent = targetItem.Parent as TreeView;
}
//Complete the drag/drop
//must be same parent to successfully drop
if(sourceItem.Parent == targetItem.Parent)
{
var indexOfDropTarget = parent.Items.IndexOf(targetItem);
parent.Items.RemoveAt(parent.Items.IndexOf(sourceItem));
parent.Items.Insert(indexOfDropTarget, sourceItem);
sourceItem.IsSelected = true;
}
}
_isDragging = false;
}
The rules of the treeview I need are that an item being dropped for reordering can only be reordered within the same parent.
The code above works great, under the assumption that the treeviews children are all treeview items, each of which contains the data structure I am interested in.
When moving my new treeview class to the bigger project, I noticed that because the treeview is bound to a collection in the view model, e.Data is no longer a treeview item! It is now the datastructure from the view model. e.Source is also no longer a treeview item, it is the entire treeview so I have no way of telling where I am "dropping" the item.
The treeview is built automatically based off the datastructure in the view model. Each item has a Children property, and each item in the Children property can have their own children. My requirement is that the items within a Children property can be reordered, but a child could not be moved to the same collection its parent is stored in or one of it's childrens' collections.
My question is this: How do I get the TreeViewItem being dragged and the TreeViewItem being dropped upon? I need to be able to see the parent of each and make sure they are the same.
Am I going about this the wrong way? Should I be passing commands back to the view model instead?
Thanks!