我正在try 用C#从类的树中构建一个WinForms树视图,它能够通过从类 struct 中搜索标记来从树视图中 Select 一项.

我一直在try 实现一个Update方法,以便在需要时以递归方式重新绘制整个树.

首先: 我在基本树中的所有类都是从一个名为Node的抽象类派生的. Node类包含一个name (string)_id (byte)和一个子 node 列表:

abstract class Node
{
    byte _id;
    string _name;
    List<Node> _children = new List<Node>();

    public Node()
    {
        this.ID = (byte)Iterator.GenerateID;
    }
    public void AddChild(Node child)
    {
        _children.Add(child);
    }
}

Node构造函数分配一个唯一的ID.(目前为止这工作正常). 这个类的任何派生类都可以成功地生成一个ID,而不会覆盖任何东西.

在我的主表单中,我有一个根 node 列表:private List<Node> _root = new List<Node>(); 和用于存储当前 Select 的 node 的变量:private Node _selection;

我用来遍历 node 列表并递归地将它们添加到我的表单的TreeView中的Update方法;tv_scene:

private void UpdateTree()
{
    tv_scene.BeginUpdate();
    tv_scene.Nodes.Clear();
    tv_scene.Nodes.Add("Scene");
    foreach (Node n in _root)
    {
        TreeNode tn = new TreeNode(n.Name);
        tn.Tag = n.ID;
        if (n.Children.Count != 0)
        {
            AddTreeItem(n, tn);
        }
        tv_scene.Nodes[0].Nodes.Add(tn);
    }
    tv_scene.ExpandAll();
    tv_scene.EndUpdate();
}

private void AddTreeItem(Node node, TreeNode parent)
{
    TreeNode tn = new TreeNode(node.Name);
    tn.Tag = node.ID;
    parent.Nodes.Add(tn);
    foreach (Node n in node.Children)
    {
        if (n.Children.Count != 0)
        {
            AddTreeItem(n, tn);
        }
    }
    return;
}

当需要对树形视图进行更新时,我会呼叫UpdateTree(). 在我的用例中,我将唯一ID作为字符串存储在TreeView node 的"tag"成员中,然后将其转换回一个字节,以便在Node树中搜索由TreeView中的项目表示的对象. 此搜索也以递归方式完成:

private Node GetNodeByID(List<Node> nodes, byte? id)
{
    foreach (Node n in nodes)
    {
        if (n.ID == id)
            return n;

        if (n.Children.Count != 0)
        {
            Node result = GetNodeByID(n.Children, id);
            if (result != null)
                return result;
        }
    }
    return null;
}

我通过将TreeView中所选项目的标记解析回一个字节来调用此搜索函数,如下所示:_selection = GetNodeByID(_root, (byte)UInt32.Parse(tv_scene.SelectedNode.Tag.ToString())); 将子 node 添加到根列表时,代码运行得很好,但每当我try 将子 node 添加到所述项目(2层深)时,新添加的子 node 显示的名称与其父 node 的名称相同,尽管使用正确的ID和名称进行了正确的初始化.另外,如果我try 用_selection = GetNodeByID(_root, (byte)UInt32.Parse(tv_scene.SelectedNode.Tag.ToString()));来 Select 该 node ,我会得到它的父 node .我也不能向所述 node 添加任何子 node ,并且树最多保持2层深.

示例:

Steps

当我打印新的item函数的输出和结果GetNodeByID()时:

Node added: [ID:0, Name:Root0]     //Adding first node(success)
Node added: [ID:1, Name:Root1]     //Adding second node(success)
Item selected: [ID:0, Name:Root0]  //Selecting the first node with GetNodeByID(success)
Node added: [ID:2, Name:Child0]    //Adding a child to the selected node (?)
Item selected: [ID:0, Name:Root0]  //Trying to select node [ID:2, Name:Child0](fail)

我非常确定我的递归方法中的逻辑在某种程度上存在根本缺陷,我只是看不出来.这里是否发生了什么阻止我显示&amp; Select 超过2个分支深度的 node ?

推荐答案

这是你的罪魁祸首:

// Coming from UpdateTree, ...
// node is n
// parent is new TreeNode(n.Name)
private void AddTreeItem(Node node, TreeNode parent)
{
    TreeNode tn = new TreeNode(node.Name); // == n.Name
    tn.Tag = node.ID;                      // == n.ID
    parent.Nodes.Add(tn);                  // == tn.Nodes.Add(tn), basically
    foreach (Node n in node.Children)
    {
        if (n.Children.Count != 0)   // btw: Children do not get added if 
                                     //      they do not have children?
        {
            AddTreeItem(n, tn);
        }
    }
    return;
}

因此,当从UpdateTree呼叫AddTreeItem时,您只需将parent加一次即可.

修复的一部分是将要添加的子元素传递给父元素,而不是父元素本身.

另一个办法是解决 children 计数的问题.

Maybe(它总是有助于me)考虑将递归转换为迭代.这对练习没有坏处,如果that对你来说更清楚,那就更好了.

Csharp相关问答推荐

循环访问Android视图中动态创建的子视图

无法将blob发送到Azure -缺少HTTP标头异常

在WPF.NET 6中使用C++/WinRT组件(但实际上是任何WinRT组件)

Regex在c#中完全匹配

如何在Visual Studio代码中更改大括号模式{},用于C#语言

如何将Kafka消息时间戳转换为C#中的日期和时间格式?

限制特定REST API不被访问,但部署代码

使用HttpResponseMessage中的嵌套列表初始化JSON

如何解决提交按钮后 Select 选项错误空参照异常

在.NET核心项目中创建Startup.cs比在Program.cs中注册服务好吗?

如何将MongoDB序列化程序设置为内部对象属性

为什么AggregateException的Catch块不足以处理取消?

如何使用用于VS代码的.NET Maui扩展在我的iOS/Android设备或模拟器上进行调试?

此异步方法在重写方法中缺少等待运算符警告

用于请求用户返回列表的C#Google API

我应该为C#12中的主构造函数参数创建私有属性吗?

C#中使用ReadOnlySpan的泛型类型推理

在Visual Studio 2022中查找Xamarin模板时遇到问题

如何在更新数据库实体时忽略特定字段?

无法创建工具窗口(用于VBIDE、VBA的COM加载项扩展)