【问题标题】:How can you use a Foreach loop to iterate data into treenode from data table nodes如何使用 Foreach 循环将数据从数据表节点迭代到 treenode
【发布时间】:2020-06-06 05:02:21
【问题描述】:

我正在尝试使用 foreach 循环创建树视图节点。我有 2 个数据表,当前正在使用 foreach 循环来获取行。我的第一个 foreach 循环成功地将第一个数据表行放入树视图节点。问题是将第二个数据表行放入每个父节点。

第一个数据表的结构是:

job       |suffix
J000027399   0
J000027399   1
J000027399   2
J000027399   3
J000027399   4
J000027399   5

第二个表结构是:

job       |suffix|operNum
J000027399  0        10
J000027399  0        20
J000027399  0        30
J000027399  1        10
J000027399  1        20
J000027399  2        10
J000027399  3        10
J000027399  4        10
J000027399  4        20
J000027399  5        10

第三个表结构是:

job       |suffix|operNum|seq|item
J000027399  0        30    1  item_1
J000027399  0        30    2  item_2
J000027399  0        30    3  item_3
J000027399  0        30    4  item_4
J000027399  1        10    1  item_1
J000027399  1        10    2  item_2
J000027399  1        10    3  item_3
J000027399  1        20    1  item_1
J000027399  1        20    2  item_2
J000027399  2        10    1  item_1
J000027399  3        10    1  item_1
J000027399  4        10    1  item_1
J000027399  4        10    2  item_2
J000027399  4        20    1  item_1
J000027399  5        10    1  item_1

我需要像这样填充树节点:

0 
 10
 20
 30
   1
   2
   3
   4
1
 10
   1
   2
   3
 20
   1
   2
2
 10
   1
3
 10
   1
4
 10
   1
   2
 20
   1
5
 10
   1

父节点基于第一个数据表后缀,子节点基于第二个数据表opernum,第三个数据表基于每个后缀节点的每个opernum下的seq。

这是我目前的代码

using (SqlDataAdapter jobAdapter = new SqlDataAdapter(cmd))
{            
    DataTable dtJ = new DataTable();
    jobAdapter.Fill(dtJ);

    foreach (DataRow jRow in dtJ.Rows)
    {
        tvBomView.Nodes.Add("job", jRow["Suffix"].ToString());
    }

    SqlCommand cmdStageTwo = new SqlCommand("dbo.CHS_Bom_View_Grab_JobRoute", conn);
    cmdStageTwo.CommandType = CommandType.StoredProcedure;
    cmdStageTwo.Parameters.Add("@Job", SqlDbType.NVarChar, 10).Value = txtJob.Text;

    using (SqlDataAdapter jobRouteAdapter = new SqlDataAdapter(cmdStageTwo))
    {
        DataTable dtJR = new DataTable();
        jobRouteAdapter.Fill(dtJR);

        foreach (TreeNode node in tvBomView.Nodes)
        {
            foreach (DataRow jrRow in dtJR.Rows)
            {
                if (node.Text != jrRow["Suffix"].ToString())
                {
                    break;
                }
                else if (node.Text == jrRow["Suffix"].ToString())
                {
                    tvBomView.Nodes["job"].Nodes.Add("oper", "Oper: " + 
                        jrRow["OperNum"].ToString());
                }
            }
        }
    }
}

【问题讨论】:

  • 我认为打破循环可能是问题所在。
  • 如果我中断它会将所有数据仅写入第一个父节点。
  • 是的,因为我已经调试了代码。第一个 foreach 循环运行,第二个循环遍历 jrRow[] 中的所有数据并填充第一个节点,即使它为假。
  • 我认为你最好加入这两个表,并使用 GroupBy 然后将其绑定到你的 TreeList。

标签: c# foreach treeview


【解决方案1】:

您可以同时加载 DataTable-s 并将它们与 TreeView 一起传递给创建树的方法:

{
//The method where you call dtJ and dtJR from the database:
ToTreeView(tvBomView, dtj, dtJR);
}

ToTreeView(..)方法:

private void ToTreeView(TreeView tv, DataTable dt1, DataTable dt2)
{
    tv.BeginUpdate();
    tv.Nodes.Clear();

    //Create a temp IEnumerable of anonymous type:
    var items = dt1.Rows.Cast<DataRow>()
        .Select(x => new
        {
            Parent = x,
            Children = dt2.Rows.Cast<DataRow>()
            .Where(y => y["suffix"].ToString() == x["suffix"].ToString())
        });

    foreach(var item in items)
    {
        var parentNode = tv.Nodes.Add("job", item.Parent["suffix"].ToString());

        foreach(var child in item.Children)
        {
            parentNode.Nodes.Add("oper", $"Oper: {child["operNum"].ToString()}");
        }
    }

    tv.EndUpdate();
}

或者只是:

private void ToTreeView(TreeView tv, DataTable dt1, DataTable dt2)
{
    tv.BeginUpdate();
    tv.Nodes.Clear();

    dt1.Rows.Cast<DataRow>()
        .ToList()
        .ForEach(x =>
        {
            var p = tv.Nodes.Add("job", x["Suffix"].ToString());
            dt2.Rows.Cast<DataRow>()
            .Where(y => x["Suffix"].ToString() == y["Suffix"].ToString())
            .ToList()
            .ForEach(y => p.Nodes.Add("oper", $"Oper: {y["operNum"].ToString()}"));
        });

    tv.EndUpdate();
}

编辑:3 表版本

private void ToTreeView(TreeView tv, DataTable dt1, DataTable dt2, DataTable dt3)
{
    tv.BeginUpdate();
    tv.Nodes.Clear();

    dt1.Rows.Cast<DataRow>()
        .ToList()
        .ForEach(x =>
        {
            var p = tv.Nodes.Add("job", x["suffix"].ToString());
            dt2.Rows.Cast<DataRow>()
            .Where(y => x["suffix"].ToString() == y["suffix"].ToString())
            .ToList()
            .ForEach(y =>
            {
                var c = p.Nodes.Add("oper", $"Oper: {y["operNum"].ToString()}");
                dt3.Rows.Cast<DataRow>()
                .Where(z => z["suffix"].ToString() == y["suffix"].ToString() &&
                z["operNum"].ToString() == y["operNum"].ToString())
                .ToList()
                .ForEach(n => c.Nodes.Add("seq", $"Seq: {n["seq"].ToString()}"));
            });
        });

    tv.EndUpdate();
}

请将此视为一种快速而简单的解决方法,并考虑 cmets 中提到的内容。查看下面的相关帖子。

相关

Populate TreeView from DataTable
Populate WinForms TreeView from DataTable
Populate TreeView from Database using C#

【讨论】:

  • 这很好用!是否可以向其中添加第三个 DataTable 并让它在 opernum 节点下创建一个子节点?我正在尝试学习 Linq,所以我只是好奇。
  • 问题是我有三个表来构建物料清单,但我不确定是否可以将这些表连接到单个 DataTable 中而无需多余的节点。
  • 谢谢!我很感激你的回复。我添加了表格并更新了 TreeView 示例以包含第三个表格的输出。
  • 当您运行代码时,会出现一条异常消息,指出 Specified cast is not valid
  • 这是完美的。我知道我的要求很高,但是有没有办法为此添加递归,所以它只需遍历两个 DataTable 并在 seq 级别填充树,因为每个 seq 都有操作数和递归的 seq。
【解决方案2】:

尝试以下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            DataTable dt = new DataTable();
            dt.Columns.Add("job", typeof(string));
            dt.Columns.Add("suffix", typeof(int));
            dt.Columns.Add("operNum", typeof(int));

            dt.Rows.Add(new object[] { "J000027399", 0, 10});
            dt.Rows.Add(new object[] { "J000027399", 0, 20});
            dt.Rows.Add(new object[] { "J000027399", 0, 30});
            dt.Rows.Add(new object[] { "J000027399", 1, 10});
            dt.Rows.Add(new object[] { "J000027399", 1, 20});
            dt.Rows.Add(new object[] { "J000027399", 2, 10});
            dt.Rows.Add(new object[] { "J000027399", 3, 10});
            dt.Rows.Add(new object[] { "J000027399", 4, 10});
            dt.Rows.Add(new object[] { "J000027399", 4, 20});
            dt.Rows.Add(new object[] { "J000027399", 5, 10});

            var groups = dt.AsEnumerable()
                .OrderBy(x => x.Field<int>("suffix"))
                .ThenBy(x => x.Field<int>("operNum"))
                .GroupBy(x => x.Field<int>("suffix"));

            foreach (var group in groups)
            {
                TreeNode node = new TreeNode(group.Key.ToString());

                treeView1.Nodes.Add(node);
                foreach (DataRow row in group)
                {
                    node.Nodes.Add(row.Field<int>("operNum").ToString());
                }

            }
            treeView1.ExpandAll();
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-24
    • 1970-01-01
    • 2021-10-18
    • 2021-01-26
    • 2020-01-22
    • 2020-10-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多