I have a WPF TreeView
with one level of child items. I am using the HierarchicalDataTemplate
for the top-level items, so the child items are bound to a backing data list.
When I'm doing dragging and dropping I want to find out where in the target list the new items should go to. I have broken the scenarios down into the following cases:
- I am on on empty part of the target
TreeView
- I am hovering on or near one of the top-level
TreeViewItem
s (dropped item must go to the back of the list) - I am hovering on one of the child-items, in which case the dropped item must go either to the front or the back of the current item, depending on whether I am hovering on the upper or lower half of the item.
My question is, how do I know which TreeViewItem
I am hovering over? How do I know if it is a parent-type or a child-type TreeViewItem
? (They have different DataContext
data types) Should I do some kind of hittesting? How do I know which top-level item owns the current child-item I am hovering over?
Here's a simpler more concise way, thanks for the direction though Pieter Breed.
After trying a bunch of things I think I've come up with a way to do this. The
DragOver
andDrop
events send you aDragEventArgs
parameter. You use this to do hit-testing. If you hittest though, you are not likely to hit the item you want directly. Rather, you are going to be hitting something that forms part of the template of the item. To get to the TreeViewItems you are interested in, you can try and walk up the Visual Tree.In this example the top-level
TreeViewItems
are bound toGroupItem
instances and the child-nodes are bound toDragItems
instances.tv
is the name of the TreeView element itself. In this code it is safe to assume that I will find it, since the event handlers are defined on this element.I created the following code that walks up the tree.
Consume it like this. Notice the check for
IsVisible
which is important:If you want to give some kind of visual indication of where the item will drop, consider using an adorner like Bea Stollnitz explains here. You may also consider changing some kind of value on the Bound data classes (like having an
IsHovering
property which can highlight the item via databinding)I think there is a simpler way to determine the drop TreeViewItem.
Inside private void Tree_Drop(object sender, DragEventArgs e), DragEventArgs e contains 'OriginalSource' of data type 'object'; during runtime, it casted to data type TextBlock. Inside 'OrginalSource', there is 'DataContext'; during runtime, it casted to object that defined in xaml for TreeViewItem. So you can get the target TreeViewItem by (e.OriginalSource as TextBlock).DataContext as XXX.