首页 > 解决方案 > 如何动态解析数据列表并在树视图中显示结果

问题描述

我有一个具有属性的对象列表。对象类如下所示:

public class ElementImpression
{
    public int ElementId { get; private set; }
    public string FamilyAndTypeName { get; private set; }
    public string CategoryName { get; private set; }
    public int CategoryNumber { get; private set; }
    public string SystemAbbreviation { get; private set; }
    public ElementImpression(Element e)
    {
        ElementId = e.Id.IntegerValue;
        FamilyAndTypeName = e.get_Parameter(BuiltInParameter.ELEM_FAMILY_AND_TYPE_PARAM).AsValueString();
        CategoryName = e.Category.Name;
        CategoryNumber = e.Category.Id.IntegerValue;
        SystemAbbreviation = e.get_Parameter(BuiltInParameter.RBS_DUCT_PIPE_SYSTEM_ABBREVIATION_PARAM).AsString();
    }
}

目标是解析列表并在 TreeView 控件中创建结构化的分层表示。层次结构中的级别数以及用作节点的属性由用户在运行时定义。我已成功创建以下树视图: Treeview使用以下代码:

private void UpdateTreeView(object sender, MyEventArgs e)
    {
        //Level 0: All
        //Level 1: System Abbreviation
        //Level 2: Category Name
        //Level 3: Family and Type Name

        treeView1.BeginUpdate();
        treeView1.Nodes.Clear();
        
        //Payload is a container object holding the list to be parsed. It is cached as a property in the form.
        //Payload.ElementsInSelection is the list of objects to parse.
        var lv1Group = Payload.ElementsInSelection.GroupBy(x => x.SystemAbbreviation);
        treeView1.Nodes.Add("All");

        int i = -1;
        foreach (IGrouping<string, ElementImpression> group1 in lv1Group)
        {
            treeView1.Nodes[0].Nodes.Add(group1.Key);

            var lv2Group = group1.ToList().GroupBy(x => x.CategoryName);

            i++;
            int j = -1;
            foreach (IGrouping<string,ElementImpression> group2 in lv2Group)
            {
                treeView1.Nodes[0].Nodes[i].Nodes.Add(group2.Key);

                var lv3Group = group2.ToList();

                j++;
                int k = -1;
                foreach (ElementImpression ei in lv3Group)
                {
                    k++;
                    treeView1.Nodes[0].Nodes[i].Nodes[j].Nodes.Add(ei.FamilyAndTypeName);

                    treeView1.Nodes[0].Nodes[i].Nodes[j].Nodes[k].Nodes.Add(ei.ElementId.ToString());
                    treeView1.Nodes[0].Nodes[i].Nodes[j].Nodes[k].Nodes.Add(ei.CategoryNumber.ToString());
                }
            }
        }
        treeView1.EndUpdate();
    }

是否可以重写 UpdateTreeView() 方法,使其接受某种对象,该对象告诉该方法使用多少级别和哪些属性,然后在运行时解析数据并动态创建树视图?是否可以使用递归来做到这一点?

标签: c#recursiondynamictreeview

解决方案


好吧,我设法找到了解决方案。它不是递归的,而是动态的。可以在运行时添加或删除属性,下面的代码应该解析它并填充树。

总体思路是遍历所有需要组织的对象,以确定最深层次节点的FullPath。因为我使用属性值作为节点,所以每个对象都已经包含了它的 FullPath 子部分。它们只需要按正确的顺序组合即可。

然后,从手动添加的顶层根节点开始,遍历路径的每一步,检查节点是否存在,是否创建它。此方法成功地在树视图中根据需要呈现我的数据。

FindTreeNodeByFullPath() 方法来自这里

public void PopulateTreeview()
    {
        //Manually add root node
        treeView1.Nodes.Add("All");
        
        //Loop all the objects
        foreach (ElementImpression e in Elements)
        {
            //Declare array to hold the names of all nodes in path to the element
            //PropertiesList is an object containing information about what properties to consider and how many.
            string[] pathParts = new string[PropertiesList.Length + 2];

            //The name of root node
            pathParts[0] = "All";

            //Populate the path parts with values from elements
            for (int i = 0; i < PropertiesList.Length; i++)
            {
                pathParts[i + 1] = PropertiesList[i].getPropertyValue(e);
            }
            //Finish the list with the name of the element (id currently)
            pathParts[pathParts.Length - 1] = e.Id.IntegerValue.ToString();

            //Create an array of all full paths from root node to the element
            string[] fullPaths = new string[PropertiesList.Length + 2];
            for (int i = 0; i < fullPaths.Length; i++)
            {
                if (i == 0) fullPaths[i] = pathParts[i];
                else fullPaths[i] = fullPaths[i - 1] + "." + pathParts[i];
            }

            //Iterate through the fullPaths to determine, if node exists, if not -> create it
            TreeNode previousNode = null;
            for (int i = 0; i < fullPaths.Length; i++)
            {
                TreeNode foundNode = treeView1.Nodes.FindTreeNodeByFullPath(fullPaths[i]);
                if (foundNode == null)
                {
                    if (previousNode != null) previousNode = previousNode.Nodes.Add(pathParts[i]);
                }
                else
                {
                    previousNode = foundNode;
                    continue;
                }
            }
        }
    }

推荐阅读