简体   繁体   English

绑定到集合时使用WPF树视图的正确方法

[英]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. 在弄乱实际项目之前,我在一个单独的项目中将treeview子类化,并为Drop,DragOver,MouseMove和DragLeave事件添加了处理程序,并在必要时实现了它们。 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. 拖放重新排序对于副项目而言效果很好,因为我对其进行了设置,以使每个TreeViewItem都可以在Header属性中存储我感兴趣的项目。

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. 我需要的treeview规则是,被删除以进行重新排序的项目只能在同一父项中进行重新排序。

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! 将新的treeview类移至更大的项目时,我注意到由于treeview绑定到视图模型中的集合,因此e.Data不再是treeview项! 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. e.Source也不再是树视图项目,而是整个树视图,因此我无法知道要“删除”该项目的位置。

The treeview is built automatically based off the datastructure in the view model. treeview是基于视图模型中的数据结构自动构建的。 Each item has a Children property, and each item in the Children property can have their own children. 每个项目都有一个Children属性,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. 我的要求是,Children属性中的项目可以重新排序,但不能将孩子移到其父级存储在的同一集合中,或者不能移动到其子级集合之一。

My question is this: How do I get the TreeViewItem being dragged and the TreeViewItem being dropped upon? 我的问题是这样的:如何将TreeViewItem拖动到并且将TreeViewItem拖放到上面? 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. 由于从视图中您没有引用子对象的直接父容器的容器,因此必须迭代地从root(treeview)找到它。

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. 我一直在寻找的项目仍存储在treeviewitem.header属性中。

If anyone else runs in to the same problem, this link will teach you everything you need 如果其他人遇到相同的问题, 此链接将教您所需的一切

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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