简体   繁体   中英

Proper way to use WPF treeview when bound to collections

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!

I think you need to find the container for your data structure. If you need the way, I have done this using this code:

TreeViewItem container = myTreeViewItem.ItemContainerGenerator.ContainerFromItem(child).As<TreeViewItem>();

you have to iterate in the tree to find the container of child. since from view you are not having reference of container of direct parent of child object, you have to find it from root(treeview) iteratively.

What I ended up doing was walking the visual tree. I was able to get the textblocks that the events first occurred on and from there it was just a matter of walking up the tree until I found the proper treeview.

The items I was looking for are still stored in the treeviewitem.header property.

If anyone else runs in to the same problem, this link will teach you everything you need

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM