代码之家  ›  专栏  ›  技术社区  ›  Pieter Breed

拖放到TreeView,查找要在其中插入已删除项的索引

  •  3
  • Pieter Breed  · 技术社区  · 15 年前

    我有一个WPF TreeView 具有一级子项。我正在使用 HierarchicalDataTemplate 对于顶级项,因此子项绑定到支持数据列表。

    当我拖放时,我想知道新项目应该放在目标列表的哪个位置。我将这些场景分解为以下几种情况:

    1. 我在目标的空位上 树视图
    2. 我在一个顶层或其附近徘徊 TreeViewItem s(删除的项目必须放在列表的后面)
    3. 我将鼠标悬停在其中一个子项上,在这种情况下,放置的项必须位于当前项的前面或后面,这取决于我将鼠标悬停在项的上半部分还是下半部分。

    我的问题是,我怎么知道 树形视图项 我在上空盘旋?我如何知道它是父类型还是子类型 树形视图项 ?(他们有不同的 DataContext 数据类型)我应该做某种测试吗?我如何知道哪个顶级项目拥有我悬停的当前子项目?

    3 回复  |  直到 6 年前
        1
  •  6
  •   Pieter Breed    15 年前

    在尝试了很多事情之后,我想我已经想出了一个办法。这个 DragOver Drop 事件向您发送 DragEventArgs 参数。你用这个做命中测试。如果你点击测试,你不太可能直接点击你想要的物品。相反,您将要访问构成项目模板一部分的内容。为了找到你感兴趣的树上项目,你可以试着走上视觉树。

    在本例中,顶层 TreeViewItems 势必 GroupItem 实例和子节点绑定到 DragItems 实例。 tv 是TreeView元素本身的名称。在这段代码中,假设我会找到它是安全的,因为事件处理程序是在这个元素上定义的。

    我创建了以下代码,这些代码在树上行走。

        private void FindDropTarget(
            out TreeViewItem pGroupingNode, 
            out TreeViewItem pItemNode,
            DragEventArgs pDragEventArgs)
        {
            pItemNode = null;
            pGroupingNode = null;
    
            DependencyObject k = VisualTreeHelper.HitTest(tv, pDragEventArgs.GetPosition(tv)).VisualHit;
    
            while (k != null)
            {
                if (k is TreeViewItem)
                {
                    TreeViewItem treeNode = k as TreeViewItem;
                    if (treeNode.DataContext is GroupItem)
                    {
                        pGroupingNode = treeNode;
                    }
                    else if (treeNode.DataContext is DragItems)
                    {
                        pItemNode = treeNode;
                    }
                } 
                else if (k == tv)
                {
                    Console.WriteLine("Found treeview instance");
                    return;
                }
    
                k = VisualTreeHelper.GetParent(k);
            }
        }
    

    像这样消费。注意支票 IsVisible 这一点很重要:

        private void tv_DragOver(object sender, DragEventArgs e)
        {
            TreeViewItem groupingNode, itemNode;
            FindDropTarget(out groupingNode, out itemNode, e);
    
            GroupItem groupingData = (groupingNode != null ? groupingNode.DataContext as GroupItem : null);
            DragItems dragItem = (itemNode != null && itemNode.IsVisible ? itemNode.DataContext as DragItems : null);
    
            Console.WriteLine("Hovering ...");
            Console.WriteLine(
                "Grouping Node = {0}, Item Node = {1}",
                groupingData != null ? groupingData.Title : "null",
                dragItem != null ? dragItem.Id : "null");
        }
    

    如果您想对项目的放置位置给出某种视觉指示,请考虑使用类似 Bea Stollnitz explains here . 您还可以考虑更改绑定数据类上的某种值(例如 IsHovering 可以通过数据绑定突出显示项的属性)

        2
  •  3
  •   Brent Hans Olsson    11 年前

    这里有一个更简单、更简洁的方法,感谢Pieter-Breed的指导。

    private void Tree_DragOver(object sender, DragEventArgs e) {
    TreeViewItem treeViewItem = FindAncestor<TreeViewItem>((DependencyObject)e.OriginalSource);
    if (treeViewItem != null) {
        treeViewItem.Background = Brushes.Blue;
    }
    }   
    private void Tree_DragLeave(object sender, DragEventArgs e) {
    TreeViewItem treeViewItem = FindAncestor<TreeViewItem>((DependencyObject)e.OriginalSource);
    if (treeViewItem != null) {
        treeViewItem.Background = Brushes.White;
    }
    }
    private static T FindAncestor<T>(DependencyObject current) where T : DependencyObject { // Search the VisualTree for specified type
    while (current != null) {
        if (current is T) {
            return (T)current;
        }
        current = VisualTreeHelper.GetParent(current);
    }
    return null;
    }
    
        3
  •  1
  •   William    6 年前

    我认为有一种更简单的方法来确定放置的树视图项。

    在私有void树_drop(对象发送方,dragEventArgs e)中,dragEventArgs e包含数据类型“object”的“originalsource”;在运行时,它强制转换为数据类型textBlock。在“OrginalSource”中,有“DataContext”;在运行时,它强制转换为在XAML中为TreeView项定义的对象。因此,您可以通过(e.originalsource as textblock).dataContext as xxx获取目标树视图项。