locked
create treenode (parent and child) for each node xml RRS feed

  • Question

  • Hello

    I have xml file for each person, it has one level of node:

     <grand name="peirre"   id="1" sex="male"  status="alive" child="2" father="0"></grand>

    <grand name="peter"   id="2" sex="male"  status="alive" child="3" father="1"></grand>

    <grand name="Jan"   id="3" sex="male"  status="alive" child="5" father="1"></grand>
    first person has attribute father with value=0, each person have father.

    i want to create treeview for this file to display the name for all person, then display his child as child treenode.

    in code: i create struct :

    public struct person
            {
                public string id;
                public string name;
                public string father;
                public string child;
            }

    person[] arr= new person[200];

    then i make one object of struct for each nodexml, as this:

      public void setlist()
            {
                int i = 0;
                while (i <200) { 
                var str = (from n in xmldoc.Descendants("grand")
                                            where n.Attribute("id").Value == (i+1).ToString()
                                            select new
                                            {
                                                Name = n.Attribute("name").Value,
                                                Sex = n.Attribute("sex").Value,
                                                Status = n.Attribute("status").Value,
                                                Child = n.Attribute("child").Value,
                                                Id = n.Attribute("id").Value,
                                                Father = n.Attribute("father").Value
                                            }).First();
                {
                    arr[i].id = str.Id.ToString();
                    arr[i].child = str.Child.ToString();
                    arr[i].name = str.Name.ToString();
                    arr[i].father = str.Father.ToString();
                }
                i += 1;
                }};

    then, i try to do what i want:

    public void createtree(){

        *            int k = 0;
        **          string mame = string.Format("{0}", arr[k].name);
        ***         treeView1.Nodes.Add(mame);
                    for ( int j = 1; j < 200; j++)
                    {
                        for (int f = 1; f < 200; f++)
                        {
                            string side1=string.Format("{0}", arr[f].father);
                            string side2=string.Format("{0}", arr[j].id);
                            if (side1 == side2)
                            {
                                mame = string.Format("{0}", arr[f].name);
                                treeView1.Nodes[k].Nodes.Add(mame);
                            }
                        }
                    }
                }

    but what i get is: the first father(person), due to the line(*,**,***), but all the other xml node become child for this father.

    I hope my story is clear for you.

    thank you

    Monday, July 20, 2015 11:07 AM

Answers

  • The first thing I notice is that k is always zero.  So you are always adding to treeView1.Nodes[0].  So each newly added node will be a child of the the first node in the treeview.

    Usually, when you build a treeview, you store the newly added node in a TreeNode variable.  Then when you want to add a child, you can target it directly without knowing its index.

    root = treeView1.Nodes.Add("root");
    child = root.Nodes.Add( "child" );
    grandchild = child.Nodes.Add( "grandchild" );
    

    In your case you are searching a list of Parent/Child pairs for all the children of a particular parent and trying add each child.  This is inefficient, but will produce correct results, provided that you can target the correct parent and do this recursively so that whenever you add a node, you immediately add all its children so that you retain the context of which TreeNode should be added to.

    Something like:

    void AddAllChildren( TreeNode parent, int parentIndex ) {
      for( int childIndex = 0; childIndex < arr.Length; ++childIndex ) {
        if( arr[childIndex].father == arr[parentIndex].id ) {
          TreeNode child = parent.Nodes.Add(arr[childIndex].name);
          AddAllChildren( child, childIndex );
        }
      }
    }

    This obviously also requires that there are no cycles in your graph -- that no child can be a descendant of itself -- otherwise it would recurse without terminating.


    • Marked as answer by olwan Monday, July 20, 2015 7:52 PM
    Monday, July 20, 2015 11:56 AM
  • I find the way you're doing things too complex for what you actually want to do. Here's my suggestion:

    First of all, your Person struct should look like this:

    public struct person
    {
    	public string Id;
    	public string Name;
    	public string Father;
    	public string Child;
    	public string Sex;
    	public string Status;
    }


    then, to build your TreeView you simply do the following:

    public static List<person> BuildTreeNode()
    {
    	XElement xmlData = XElement.Load("<your_xml_file_url_here>");
    	List<person> personsList = new List<person>();
    	//or use this if you have it in a string: XElement xmlData = XElement.Parse(stringContainingXML);
    	person currentPerson;
    	TreeNode currentTreeNode;
    	foreach (XElement element in xmlData.Descendants("grand"))
    	{
    		currentPerson = new person()
    		{
    			Name = element.Attribute("name").Value,
    			Sex = element.Attribute("sex").Value,
    			Status = element.Attribute("status").Value,
    			Child = element.Attribute("child").Value,
    			Id = element.Attribute("id").Value,
    			Father = element.Attribute("father").Value
    		};
    		personsList.Add(currentPerson);
    		currentTreeNode = new TreeNode() { Name = currentPerson.Id };
    		currentTreeNode.Tag = currentPerson;
    		if (treeView.Nodes.ContainsKey(currentPerson.Id))
    			treeView.Nodes[currentPerson.Id].Nodes.Add(currentTreeNode);
    		else
    			treeView.Nodes.Add(currentTreeNode);
    	}
    	return personsList;
    }

    This way you also gain a binding between the returned personsList and your treeView: each TreeNode corresponds to a person. Of course you should fill in the Text property of your node after construction, that depends on how you want it to look (contains the name? a concatenation of name and other stuff? your choice).

    I hope this helps

    • Proposed as answer by Yazid HAMDI Monday, July 20, 2015 12:07 PM
    • Marked as answer by olwan Monday, July 20, 2015 7:52 PM
    Monday, July 20, 2015 12:07 PM

All replies

  • The first thing I notice is that k is always zero.  So you are always adding to treeView1.Nodes[0].  So each newly added node will be a child of the the first node in the treeview.

    Usually, when you build a treeview, you store the newly added node in a TreeNode variable.  Then when you want to add a child, you can target it directly without knowing its index.

    root = treeView1.Nodes.Add("root");
    child = root.Nodes.Add( "child" );
    grandchild = child.Nodes.Add( "grandchild" );
    

    In your case you are searching a list of Parent/Child pairs for all the children of a particular parent and trying add each child.  This is inefficient, but will produce correct results, provided that you can target the correct parent and do this recursively so that whenever you add a node, you immediately add all its children so that you retain the context of which TreeNode should be added to.

    Something like:

    void AddAllChildren( TreeNode parent, int parentIndex ) {
      for( int childIndex = 0; childIndex < arr.Length; ++childIndex ) {
        if( arr[childIndex].father == arr[parentIndex].id ) {
          TreeNode child = parent.Nodes.Add(arr[childIndex].name);
          AddAllChildren( child, childIndex );
        }
      }
    }

    This obviously also requires that there are no cycles in your graph -- that no child can be a descendant of itself -- otherwise it would recurse without terminating.


    • Marked as answer by olwan Monday, July 20, 2015 7:52 PM
    Monday, July 20, 2015 11:56 AM
  • I find the way you're doing things too complex for what you actually want to do. Here's my suggestion:

    First of all, your Person struct should look like this:

    public struct person
    {
    	public string Id;
    	public string Name;
    	public string Father;
    	public string Child;
    	public string Sex;
    	public string Status;
    }


    then, to build your TreeView you simply do the following:

    public static List<person> BuildTreeNode()
    {
    	XElement xmlData = XElement.Load("<your_xml_file_url_here>");
    	List<person> personsList = new List<person>();
    	//or use this if you have it in a string: XElement xmlData = XElement.Parse(stringContainingXML);
    	person currentPerson;
    	TreeNode currentTreeNode;
    	foreach (XElement element in xmlData.Descendants("grand"))
    	{
    		currentPerson = new person()
    		{
    			Name = element.Attribute("name").Value,
    			Sex = element.Attribute("sex").Value,
    			Status = element.Attribute("status").Value,
    			Child = element.Attribute("child").Value,
    			Id = element.Attribute("id").Value,
    			Father = element.Attribute("father").Value
    		};
    		personsList.Add(currentPerson);
    		currentTreeNode = new TreeNode() { Name = currentPerson.Id };
    		currentTreeNode.Tag = currentPerson;
    		if (treeView.Nodes.ContainsKey(currentPerson.Id))
    			treeView.Nodes[currentPerson.Id].Nodes.Add(currentTreeNode);
    		else
    			treeView.Nodes.Add(currentTreeNode);
    	}
    	return personsList;
    }

    This way you also gain a binding between the returned personsList and your treeView: each TreeNode corresponds to a person. Of course you should fill in the Text property of your node after construction, that depends on how you want it to look (contains the name? a concatenation of name and other stuff? your choice).

    I hope this helps

    • Proposed as answer by Yazid HAMDI Monday, July 20, 2015 12:07 PM
    • Marked as answer by olwan Monday, July 20, 2015 7:52 PM
    Monday, July 20, 2015 12:07 PM