【问题标题】:Hide Node in Treeview List. in C#在树视图列表中隐藏节点。在 C# 中
【发布时间】:2015-02-28 05:00:14
【问题描述】:

我正在使用 VS 2005 C#,正在处理未完成的 WinForm。

我已将 XML 解析为树视图列表,但遇到了一些问题。 我想知道是否有一种方法可以隐藏/过滤/删除名称中包含“_this_text”的某个节点,而无需依赖文本框。

这就是我为这个程序所做的(感谢那些帮助我开发这个程序的人):

#region "***** XML Parsing *****"
    private void Form1_Load_1(object sender, EventArgs e)
    {
        // Initialize the controls and the form.
        //label1.Text = "File Path";
        textBox2.Text = Application.StartupPath + "\\Continental.vsysvar";
        //button6.Text = "XML";
        //this.Text = "Software Validation";
    }

    private TreeNode selectedNode = null;

    private void button6_Click(object sender, EventArgs e)
    {
        try
        {
            // SECTION 1. Create a DOM Document and load the XML data into it.
            XmlDocument dom = new XmlDocument();
            dom.Load(textBox2.Text);

            // SECTION 2. Initialize the TreeView control.
            treeView1.Nodes.Clear();
            /*treeView1.Nodes.Add(new TreeNode(dom.DocumentElement.Name));
            TreeNode tNode = new TreeNode();
            tNode = treeView1.Nodes[0];*/

            foreach (XmlNode node in dom.DocumentElement.ChildNodes)
            {
                if (node.Name == "namespace" && node.ChildNodes.Count == 0 && string.IsNullOrEmpty(GetAttributeText(node, "name")))
                    continue;
                AddNode(treeView1.Nodes, node);
            }

            treeView1.ExpandAll();
        }
        /* catch (XmlException xmlEx)
         {
             MessageBox.Show(xmlEx.Message);
         }*/
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }

    private void LoadTreeFromXmlDocument(XmlDocument dom)
    {
        try
        {
            // SECTION 2. Initialize the TreeView control.
            treeView1.Nodes.Clear();

            // SECTION 3. Populate the TreeView with the DOM nodes.
            foreach (XmlNode node in dom.DocumentElement.ChildNodes)
            {
                if (node.Name == "namespace" && node.ChildNodes.Count == 0 && string.IsNullOrEmpty(GetAttributeText(node, "name")))
                    continue;
                AddNode(treeView1.Nodes, node);
            }

            treeView1.ExpandAll();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }

    static string GetAttributeText(XmlNode inXmlNode, string name)
    {
        XmlAttribute attr = (inXmlNode.Attributes == null ? null : inXmlNode.Attributes[name]);
        return attr == null ? null : attr.Value;
    }

    private void AddNode(TreeNodeCollection nodes, XmlNode inXmlNode)
    {
        if (inXmlNode.HasChildNodes)
        {
            string text = GetAttributeText(inXmlNode, "name");
            if (string.IsNullOrEmpty(text))
                text = inXmlNode.Name;
            TreeNode newNode = nodes.Add(text);
            XmlNodeList nodeList = inXmlNode.ChildNodes;
            for (int i = 0; i <= nodeList.Count - 1; i++)
            {
                XmlNode xNode = inXmlNode.ChildNodes[i];
                AddNode(newNode.Nodes, xNode);
            }
        }
        else
        {
            // If the node has an attribute "name", use that.  Otherwise display the entire text of the node.
            string text = GetAttributeText(inXmlNode, "name");
            if (string.IsNullOrEmpty(text))
                text = (inXmlNode.OuterXml).Trim();
            TreeNode newNode = nodes.Add(text);
        }
    }
    #endregion

这里是 XMl 文件的摘录,因为它很长:

    <?xml version="1.0" encoding="utf-8"?>
<systemvariables version="4">
  <namespace name="" comment="">
    <namespace name="_01_Test_Preparation" comment="">
      <variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_02_Shipping_Status_Check" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" />
      <variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_02_Shipping_Status_Check_start" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" />
      <variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_01_Get_Dem_ID" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" />
      <variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_01_Get_Dem_ID_start" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" />
      <variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_04_ECU_Version_Check_start" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" />
      <variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_03_Test_Run_Init" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" />
      <variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_04_ECU_Version_Check" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" />
      <variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_05_DEM_Reader" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" />
      <variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_03_Test_Run_Init_start" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" />
      <variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_05_DEM_Reader_start" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" />
    </namespace>

我真正想要完成的是隐藏或过滤在其名称中找到包含此文本“_start”的节点。因此,所有名称中包含“_this_start”的节点都将对用户隐藏。我已经读到,从技术上讲,启用或禁用可见性是不可能的,而是将文本变灰等等。

提前谢谢你。

【问题讨论】:

  • 它们会再次出现吗?还是他们永远隐藏?从 XML 构建树的过程应该不会太昂贵。因此,除非它很大或经常更改,否则我会考虑每次都重建整个树,不包括“不可见”的节点。
  • 它应该对用户隐藏,但实际上不能从 xml 文件本身中删除。我尝试删除名称中包含“_start”的变量,而外部程序无法正常运行。所以同名的变量只有那个区别,功能相同但不能单独操作,显然必须成对。

标签: c# winforms xml-parsing treeview


【解决方案1】:

从您的问题中不清楚过滤器是静态的还是可以由用户配置。假设过滤器可以动态配置,您可以做的是在过滤器更改时(重新)从 XML 加载树,回收现有节点,根据需要创建新节点,并删除过滤节点。 (当然,如果过滤器是静态的,这也可以。)

首先,提取一个辅助方法以从 XML 中重新填充树,并在适当的时候按名称回收节点:

public delegate string GetString<T>(T input); // No Func<T, TResult> in c# 2.0

public static class XmlTreeViewHelper
{
    public static void AddOrMergeNodes(TreeNodeCollection treeNodeCollection, XmlNodeList xmlNodeList, GetString<XmlNode> getNodeName, GetString<XmlNode> getNodeText, Predicate<XmlNode> filter)
    {
        Dictionary<string, List<TreeNode>> dict = ToNodeDictionary(treeNodeCollection);
        int index = 0;
        foreach (XmlNode inXmlNode in xmlNodeList)
        {
            AddOrMergeNode(treeNodeCollection, inXmlNode, ref index, getNodeName, getNodeText, filter, dict);
        }

        foreach (List<TreeNode> list in dict.Values)
            foreach (TreeNode leftover in list)
            {
                treeNodeCollection.Remove(leftover);
            }
    }

    static bool IsNodeAtIndex(TreeNodeCollection nodes, TreeNode node, int index)
    {
        // Avoid n-squared nodes.IndexOf(node).
        if (index < 0 || index >= nodes.Count)
            return false;
        return nodes[index] == node;
    }

    static void AddOrMergeNode(TreeNodeCollection treeNodeCollection, XmlNode inXmlNode, ref int index, GetString<XmlNode> getNodeName, GetString<XmlNode> getNodeText, Predicate<XmlNode> filter, Dictionary<string, List<TreeNode>> dict)
    {
        if (filter != null && !filter(inXmlNode))
            return;

        string treeName = getNodeName(inXmlNode);
        string treeText = (getNodeText == null ? treeName : getNodeText(inXmlNode));

        bool added = false;

        TreeNode treeNode;
        if (!DictionaryExtensions.TryRemoveFirst(dict, treeName, out treeNode))
        {
            treeNode = new TreeNode();
            treeNode.Name = treeName;
            treeNode.Text = treeText;
            added = true;
            treeNodeCollection.Insert(index, treeNode);
        }
        else
        {
            if (!IsNodeAtIndex(treeNodeCollection, treeNode, index))
            {
                treeNodeCollection.Remove(treeNode);
                treeNodeCollection.Insert(index, treeNode);
            }
        }

        index++;

        if (treeNode.Text != treeText)
            treeNode.Text = treeText;

        if (inXmlNode.HasChildNodes)
            AddOrMergeNodes(treeNode.Nodes, inXmlNode.ChildNodes, getNodeName, getNodeText, filter);
        else
            treeNode.Nodes.Clear();

        if (added)
            treeNode.ExpandAll();
    }

    /// <summary>
    /// Returns a dictionary of tree nodes by node name.
    /// </summary>
    /// <param name="nodes"></param>
    /// <returns></returns>
    static Dictionary<string, List<TreeNode>> ToNodeDictionary(TreeNodeCollection nodes)
    {
        Dictionary<string, List<TreeNode>> dict = new Dictionary<string, List<TreeNode>>();
        foreach (TreeNode node in nodes)
            DictionaryExtensions.Add(dict, node.Name, node);
        return dict;
    }
}

public static class DictionaryExtensions
{
    public static void Add<TKey, TValueList, TValue>(IDictionary<TKey, TValueList> listDictionary, TKey key, TValue value)
        where TValueList : IList<TValue>, new()
    {
        if (listDictionary == null)
            throw new ArgumentNullException();
        TValueList values;
        if (!listDictionary.TryGetValue(key, out values))
            listDictionary[key] = values = new TValueList();
        values.Add(value);
    }

    public static bool TryGetValue<TKey, TValueList, TValue>(IDictionary<TKey, TValueList> listDictionary, TKey key, int index, out TValue value)
        where TValueList : IList<TValue>
    {
        TValueList list;
        if (!listDictionary.TryGetValue(key, out list))
            return Returns.False(out value);
        if (index < 0 || index >= list.Count)
            return Returns.False(out value);
        value = list[index];
        return true;
    }

    public static bool TryRemoveFirst<TKey, TValueList, TValue>(IDictionary<TKey, TValueList> listDictionary, TKey key, out TValue value)
        where TValueList : IList<TValue>
    {
        TValueList list;
        if (!listDictionary.TryGetValue(key, out list))
            return Returns.False(out value);
        int count = list.Count;
        if (count > 0)
        {
            value = list[0];
            list.RemoveAt(0);
            if (--count == 0)
                listDictionary.Remove(key);
            return true;
        }
        else
        {
            listDictionary.Remove(key); // Error?
            return Returns.False(out value);
        }
    }
}

public static class Returns
{
    public static bool False<TValue>(out TValue value)
    {
        value = default(TValue);
        return false;
    }
}

接下来,动态(重新)加载 XML 并应用适当的过滤器:

    private void ReloadTreeFromXmlDocument(XmlDocument dom)
    {
        treeView1.BeginUpdate();
        try
        {
            XmlTreeViewHelper.AddOrMergeNodes(treeView1.Nodes, dom.DocumentElement.ChildNodes, GetTreeNodeName, GetTreeNodeText, FilterNode);
        }
        finally
        {
            treeView1.EndUpdate();
        }
    }

    static string GetTreeNodeName(XmlNode inXmlNode)
    {
        string text = GetAttributeText(inXmlNode, "name");
        if (string.IsNullOrEmpty(text))
            text = inXmlNode.Name;
        return text;
    }

    static string GetTreeNodeText(XmlNode inXmlNode)
    {
        string text = GetAttributeText(inXmlNode, "name");
        if (string.IsNullOrEmpty(text))
        {
            if (inXmlNode.HasChildNodes)
            {
                text = inXmlNode.Name;
            }
            else
            {
                text = (inXmlNode.OuterXml).Trim();
            }
        }
        return text;
    }

    string filter = "_start"; // Reload when this changes

    bool FilterNode(XmlNode inXmlNode)
    {
        return FilterNode(inXmlNode, filter /*filterComboBox.Text*/);
    }

    bool FilterNode(XmlNode inXmlNode, string nodeNameFilter)
    {
        if (inXmlNode.Name == "namespace" && inXmlNode.ChildNodes.Count == 0 && string.IsNullOrEmpty(GetAttributeText(inXmlNode, "name")))
            return false;
        if (!string.IsNullOrEmpty(nodeNameFilter))
        {
            string text = GetTreeNodeText(inXmlNode);
            if (text.Contains(nodeNameFilter))
                return false;
        }
        return true;
    }

    static string GetAttributeText(XmlNode inXmlNode, string name)
    {
        XmlAttribute attr = (inXmlNode.Attributes == null ? null : inXmlNode.Attributes[name]);
        return attr == null ? null : attr.Value;
    }

将我的解决方案反向移植到 .Net 2.0 后,我得到了以下结果:

【讨论】:

  • 除了 system.xml 之外,我是否必须包含其他命名空间?而且,我使用的版本是旧的,所以其他类型无法被 VS 识别。
  • @Kurisuchin - 我删除了 Linq 命名空间的使用和所有 var 关键字的使用,所以我认为这应该是 c#-2.0 干净的。
  • 我认为 .TryRemoveFirst 也不兼容 c#2.0。对此我感到非常抱歉,试图请求授予我更新的版本。被拒绝。
  • 你有什么可以代替的吗? (!dict.TryRemoveFirst(treeName, out treeNode))我的同事对您提供的代码进行了一些编辑,但为了弥补 TryRemoveFirst 但没有运气。
  • @Kurisuchin - 立即尝试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多