Populate TreeView From Custom Object Using Serializer


From time to time I need to spit out the public properties of an object for various reasons.  A typical use would be to show user friendly results from a web service that returns a complex object.  There could be tons of other uses!  After doing this a few times, I finially decided to post this so I can always reference it.  Anytime I do any recursive methods, it always takes me a couple of tweaks before getting it right.

The idea is that I have a custom object that I need to spin through to populate a TreeView. I created a couple of simple methods to do such. I though about using Reflection, but my method starting getting larger and larger because I was having to put in special code to handle certain Types (i.e. String, ICollection, etc). Since my typical Use Case was to spit out the results of a complex object returned from a ASMX or WCF service, I decided to go the Serialize route. My DTO class was typically already decorated with the [Serializable] attribute, if not, it was simple enought to add.

So first we serialize the object into a string of XML, then stuff that into a XmlDocument. Then you can loop through the elements while creating each TreeViewNode. That’s it!

        public void PopulateTreeView(object obj, TreeView tv)
        {
            System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
            System.Text.StringBuilder sb = new System.Text.StringBuilder();  // StringBuilder to hold the XML
            using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(sb))
            {
                serializer.Serialize(writer, obj); // Serialize the object to XML
                System.Xml.XmlDocument xDoc = new System.Xml.XmlDocument();
                xDoc.LoadXml(sb.ToString());  // Shove it in a XmlDocument
                tv.Nodes.Add(PopulateNode(xDoc));  // Add the Nodes to the TreeView
            }
        }

        public TreeNode PopulateNode(System.Xml.XmlNode node)
        {
            TreeNode treenode = new TreeNode(node.Name);  // Add the Name to the Node
            if (node.ChildNodes.Count == 1) //Prevents ParentNode from displaying all of the InnerText
                treenode.Text += "=" + node.InnerText; // If only 1 ChildNode then add the InnerText

            for (int i = 0; i < node.ChildNodes.Count; i++)
            {
                if (node.ChildNodes[i].HasChildNodes)
                {
                    treenode.ChildNodes.Add(PopulateNode(node.ChildNodes[i]));
                }
            }
            return treenode;
        }

Then call the method to populate where “customObject” is the object you want displayed in your TreeView:

            PopulateTreeView(customObject, TreeView1);

, ,

  1. #1 by Andre Brus on February 2, 2011 - 3:47 am

    Hello Eric,
    Ik saw your excellent example of “Populate TreeView From Custom Object Using Serializer”.
    It seems to work well for my custom business objects, apart from 1 thing: when a field in my custom business objects has a value of NULL, it isn’t shown AT ALL in the treeview… It is just skipped. I would have expected/liked to see it in the treeview, shown as something like (for a NULL zipcode):
    Street: Abbey Road
    ZipCode: n/a
    Housenumber: 13
    Do you have an addition for your code to make this possible?
    Thanks & Kind Regards, Andre Brus, Holland.

  2. #2 by Eric on February 3, 2011 - 3:42 pm

    Hello Andre,

    There are two issues that is causing the NULL properties to not show up. The first is that by default the XmlSerializer will not serialize a null value. You can force it to do so by decorating your property with XmlElement(IsNullalble=true) attribute:

    [System.Xml.Serialization.XmlElement(IsNullable = true)]
    public string NullableValueHere { get; set; }

    That alone won’t fix your problem. We also need to tweak the code to check for “null” value in the xml. The XmlSerializer will add the attribute “xsi:nil=true” to the element. So we can look for that:

    public TreeNode PopulateNode(System.Xml.XmlNode node)
    {
    TreeNode treenode = new TreeNode(node.Name); // Add the Name to the Node
    if (node.ChildNodes.Count == 1) //Prevents ParentNode from displaying all of the InnerText
    treenode.Text += "=" + node.InnerText; // If only 1 ChildNode then add the InnerText

    for (int i = 0; i < node.ChildNodes.Count; i++)
    {
    if (node.ChildNodes[i].HasChildNodes || IsNull(node.ChildNodes[i]))
    {
    treenode.ChildNodes.Add(PopulateNode(node.ChildNodes[i]));
    }
    }
    return treenode;
    }

    public bool IsNull(System.Xml.XmlNode node)
    {
    if (node.Attributes != null)
    {
    for (int i = 0; i < node.Attributes.Count; i++)
    {
    if (node.Attributes[i].Name == "xsi:nil")
    {
    return Convert.ToBoolean(node.Attributes[i].Value);
    }
    }
    }
    return false;
    }

    -----------------------------------
    You can try that out and see if it works for you. I didn't fully test that code...and maybe it could be written better...but I think it will do what you are needing it to do.

(will not be published)


Comments are closed.