You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#实现TreeView选中父节点时在DataGridView显示所有子节点

解决TreeView选中父节点显示所有层级子节点到DataGridView的问题

看起来你已经搭好了基础的TreeView和DataGridView框架,现在就差实现选中父节点时拉取所有层级子节点的逻辑了。先给你梳理下问题所在,再给出两种可行的解决方案:

第一步:给TreeView节点绑定技工ID

你现在的TreeNode只显示了技工姓名,没有存储对应的ID_Mechanic,导致选中节点时没法定位到对应的父节点ID。先修改你的FillTree方法,把ID存到节点的Tag属性里:

public void FillTree(TreeNodeCollection tn, int? id)
{
    NpgsqlCommand cmdtreeview;
    if (id == null)
    {
        cmdtreeview = new NpgsqlCommand("select * from mechanic where id_chief is null", ncon);
    }
    else
    {
        cmdtreeview = new NpgsqlCommand("select * from mechanic where id_chief = @id_mechanic", ncon);
        cmdtreeview.Parameters.Add(new NpgsqlParameter("id_mechanic", id));
    }
    
    NpgsqlDataAdapter da = new NpgsqlDataAdapter(cmdtreeview);
    DataTable dt = new DataTable();
    da.Fill(dt);
    
    foreach (DataRow dr in dt.Rows)
    {
        string nodeText = $"{dr["name"]} {dr["surname"]}";
        TreeNode node = new TreeNode(nodeText);
        // 把技工ID绑定到Tag,后续选中节点时能直接获取
        node.Tag = dr["id_mechanic"];
        tn.Add(node);
        FillTree(node.Nodes, (int?)dr["id_mechanic"]);
    }
}

方案一:用PostgreSQL递归CTE查询(推荐,适合大数据量)

利用PostgreSQL的递归CTE语法,直接从数据库查询该父节点下所有层级的子节点,性能比内存筛选更好:

private void treeViewMechanic_AfterSelect(object sender, TreeViewEventArgs e)
{
    // 根节点(无上级)可根据需求决定是否处理
    if (e.Node.Tag == null)
    {
        dataGridViewMechanic.DataSource = null;
        return;
    }
    
    int parentId = (int)e.Node.Tag;
    
    // 递归CTE查询所有层级子节点
    string recursiveQuery = @"
        WITH RECURSIVE sub_mechanics AS (
            -- 初始查询:直接子节点
            SELECT * FROM mechanic WHERE id_chief = @parentId
            UNION ALL
            -- 递归查询:子节点的子节点
            SELECT m.* FROM mechanic m
            JOIN sub_mechanics sm ON m.id_chief = sm.id_mechanic
        )
        SELECT * FROM sub_mechanics;
    ";
    
    using (NpgsqlCommand cmd = new NpgsqlCommand(recursiveQuery, ncon))
    {
        cmd.Parameters.Add(new NpgsqlParameter("parentId", parentId));
        NpgsqlDataAdapter da = new NpgsqlDataAdapter(cmd);
        DataTable childDt = new DataTable();
        da.Fill(childDt);
        
        // 绑定到DataGridView
        dataGridViewMechanic.DataSource = childDt;
    }
}

方案二:内存中递归筛选(适合小数据量)

如果你的技工数据量不大,也可以提前把所有数据加载到全局DataTable中,然后在内存里递归筛选所有子节点:

// 假设mechanicdt是全局已加载所有技工数据的DataTable
private void treeViewMechanic_AfterSelect(object sender, TreeViewEventArgs e)
{
    if (e.Node.Tag == null)
    {
        dataGridViewMechanic.DataSource = null;
        return;
    }
    
    int parentId = (int)e.Node.Tag;
    DataTable childTable = mechanicdt.Clone(); // 复制表结构
    
    // 递归添加所有层级子节点
    AddAllChildNodes(parentId, childTable);
    
    dataGridViewMechanic.DataSource = childTable;
}

private void AddAllChildNodes(int parentId, DataTable targetTable)
{
    // 筛选当前父节点的直接子节点
    DataRow[] directChildren = mechanicdt.Select($"id_chief = {parentId}");
    foreach (DataRow row in directChildren)
    {
        targetTable.ImportRow(row);
        // 递归添加子节点的子节点
        int childId = (int)row["id_mechanic"];
        AddAllChildNodes(childId, targetTable);
    }
}

为什么你之前的尝试没成功?

  • 用DataRelation的方式默认只显示直接子节点(一级),要显示所有层级需要额外处理,不如直接用递归查询更直观。
  • 你尝试的LINQ写法筛选条件错误:i.Field<String>("ID_Mechanic") == null是找没有ID的记录,完全不是筛选子节点的逻辑,自然得不到正确结果。

内容的提问来源于stack exchange,提问作者ma name jeff

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:26:43