从 Tree 对象填充树视图

本文关键字:填充 视图 对象 Tree | 更新日期: 2023-09-27 18:34:03

我需要在TreeView中显示一个Tree<T>层次结构,区分树节点和树叶。

Tree 对象是在运行时构造的,并且不知道其深度。不是二叉树。这是数据树类:

public class TreeNode<T> : IEnumerable<TreeNode<T>> 
{
    public T Data   {   get; set;   }
    public TreeNode<T> Parent {get; set;}
    public ICollection<TreeNode<T>> Children {get; set;}
.....
.....
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    public IEnumerator<TreeNode<T>> GetEnumerator()
    {
        yield   return this;
        foreach (var directChild in this.Children)
        {
            foreach (var anyChild   in directChild)
                yield   return anyChild;
        }
    }
}

这是填充树视图的代码:

public void CreateTreeView()
{
    AttributesTreeView=new TreeView();
    foreach(TreeNode<string> entry in NewAttTree)
    {
        if(entry.Children.Count>0)
        {
            int tn=AttributesTreeView.Nodes.Add(new TreeNode(entry.Data.ToString().Replace("|",string.Empty)));
            foreach(TreeNode<string> str in entry.Children)
            {
                if(tn!=0)
                {
                    int itn=AttributesTreeView.Nodes[tn].Nodes.Add(new TreeNode(str.Data.ToString()));
                }
            }
        }
    }
}

从 Tree<T> 对象填充树视图

你在这里做的是采用一棵树,并将该树中的每个节点投影到其他东西中,同时保持该树的结构。 这实际上相当简单。 只需创建一个查找,将每个节点映射到其所有子节点,然后遍历每个节点,查找"自己",然后将查找中的所有子节点添加到新节点:

var roots = new TreeNode<string>[] { }; //the original data to map
var lookup = roots.SelectMany(node => node)
    .ToLookup(node => node.Parent, node => new
{
    node,
    UINode = new TreeNode(node.Data),
});
foreach (var pair in lookup.SelectMany(group => group))
    foreach (var child in lookup[pair.node])
        pair.UINode.Nodes.Add(child.UINode);
TreeView view = new TreeView();
foreach (var root in lookup[null]) //assume nodes with a null parent are roots
    view.Nodes.Add(root.UINode);

我可以想到三种方法来加载DataTreeNode结构的子集:

  1. 筛选:从旧结构创建新的 DataTreeNode 结构,不包括包含不需要的叶节点的子树。 加载结果。
  2. 向 DataTreeNode 添加一个属性,该属性表示其子树的叶节点(如霍夫曼树)中的值范围。 然后在加载时,在添加给定的 DataTreeNode 之前检查属性。
  3. 对于每个 DataTreeNode,创建一个 TreeNode,但如果其子树的叶节点与所需值不匹配,则丢弃该 TreeNode。

下面是选项 3 的伪代码,使用 HashSet 查找所需的叶节点值。

void LoadDataTreeNode(TreeView treeView, DataTreeNode<T> dataTreeNode, HashSet<T> hashSet)
{
    treeView.Nodes.Clear();
    LoadDataTreeNode(treeView.Nodes, dataTreeNode, hashSet);
}

bool LoadDataTreeNode(TreeNodeCollection treeNodes, DataTreeNode<T> dataTreeNode, HashSet<T> hashSet)
{
    bool result = hashSet.Contains(dataTreeNode.Data);
    if (result)
    {
        var treeNode = new TreeNode(dataTreeNode.Data.ToString());
        // Use this treeNode if at least one of its subtrees contains
        // the required leaf node values.  Assume that all other
        // subtrees will be discarded by the relevant recursive calls.
        result = false;
        foreach (var child in dataTreeNode.Children)
        {
            if (LoadDataTreeNode(treeNode.Nodes, child, hashSet))
            {
                result = true;
            }
        }
        if (result)
        {
            treeNodes.Add(treeNode);
        }
   }
    return result;
}

好的,知道了。

TreeNode newNode=new TreeNode("SEARCH");
AttributesTreeView.Nodes.Add(newNode);
CreateTreeView(NewAttTree,newNode);

public void CreateTreeView(DataTreeNode<string> root, TreeNode parentNode)
{
    foreach(DataTreeNode<string> node in root.Children)
    {
        try
        {
            TreeNode newNode=new TreeNode(node.Data.ToString());
            parentNode.Nodes.Add(newNode);
            CreateTreeView(node,newNode);
        }
        catch (System.Exception e)
        {
        }
    }

@groverboy:感谢您朝着正确的方向推动。

还有一个问题:我们如何扫描数据树结构并仅使用具有特定值的叶子的节点填充树视图。我的意思是在DFT遍历中,我们如何决定在访问叶子并确定是否以及哪些符合过滤条件之前添加一个节点?

> @groverboy:我尝试了你的方法,但它不起作用,我注意到它永远不会通过第一个 if 子句,除非根 DataTreeNode 符合要求,否则它根本不迭代数据树。这是我根据您的代码想出的方法:它有效,但多次添加相同的分支,我一定是盲人,但我看不出为什么;也许是另一双眼睛。

bool PopulateTreeNode(DataTreeNode<string> dataNode,TreeNode treeNodes,string filter,bool ignoreCase)
    {
        if(dataNode.IsLeaf)
        {
            if(WcMatchExtensionMethods.WcMatches(dataNode.Data,filter,ignoreCase))
            {
                treeNodes.Nodes.Add(new TreeNode(dataNode.Data.ToString()));
                return true;
            }
            else
                return false;
        }
        bool result = false;
        TreeNode treeNode=new TreeNode(dataNode.Data.ToString());
        foreach (DataTreeNode<string> child in dataNode.Children)
        {
            if(PopulateTreeNode(child,treeNode,filter,ignoreCase))
            {
                treeNodes.Nodes.Add(treeNode);
                result = true;
            }
        }
        return result;
    }