Hide Node in Treeview List. in C#

你说的曾经没有我的故事 提交于 2019-12-24 05:18:06

问题


I am using VS 2005 C#, working on an unfinished WinForm.

I have parsed an XML to a treeview listing but I'm encountering some problems. I wanna know if there's a way to hide/filter/remove a certain node containing a "_this_text" in its name without having to depend on a textbox.

This is what I have for the program (kudos to those who helped me develop this):

#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

And here's an excerpt of the XMl file since it's quite long:

    <?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>

What I really want to accomplish is to hide or filter the nodes containing this text "_start" found in their name. So all nodes containing "_this_start" in their name would be hidden from the user. I've read that it is not technically possible to enable or disable visibility but instead gray out the text and whatnot.

Thank you in advance.


回答1:


It's not clear from your question whether the filter is static or can be configured by the user. Assuming that the filter can be configured dynamically, what you could do is to (re)load the tree from the XML whenever the filter changes, recycling existing nodes, creating new nodes as needed, and deleting filtered nodes. (Of course, this also works if the filter is static.)

First, extract a helper method to repopulate a tree from XML, recycling nodes by name when appropriate:

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;
    }
}

Next, dynamically (re)load the XML and apply whatever filter is appropriate:

    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;
    }

After backporting my solution to .Net 2.0, this is what I get:



来源:https://stackoverflow.com/questions/28711092/hide-node-in-treeview-list-in-c-sharp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!