Search code examples
c#wpftreeviewhierarchicaldatatemplate

C# WPF recursive duplicate nested hierarchy of elements


I have created treeview with dynamically filled from xml file hierarchy and I have issue. In treeview nested hierarchy was recursive duplicate and get result like this :

enter image description here

XAML-markup of treeview:

<TreeView x:Name="leftNestingTreeView" ItemsSource="{Binding Fragments, UpdateSourceTrigger=PropertyChanged}">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding ChildFragments}" DataType="{x:Type a:FragmentModel}">
            <TextBlock  Text = "{Binding fragmentId}"/>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

Code of source:

Fragments = NestingTree.Values.ToList();
OnPropertyChanged(nameof(Fragments));

XML file:

<NestingTree>
  <fragment id="root_fragment" name=" n1">
    <parent id="" name="" />
    <childs count="1">
      <child id="f1" name="frag1" />
    </childs>
  </fragment>
    <fragment id="f1" name="frag1">
    <parent id="root_fragment" name="n1" />
    <childs count="1">
      <child id="f2" name="frag2" />
    </childs>
  </fragment>
  <fragment id="f2" name="frag2">
    <parent id="f1" name="frag1" />
    <childs count="0" />
  </fragment>
</NestingTree>

UPDATE

NestingTree is Dictionary<string,FragmentModel>, where keys is ids and values is fragments.

Code of FragmentModel:

public class FragmentModel : INotifyPropertyChanged
{
    public string fragmentId { get; set; }    
    private string fragmentName { get; set; }    
    public string FragmentName
    {
        get { return fragmentName; }
        set 
        { 
           fragmentName = value; 
           OnPropertyChanged(nameof(FragmentName)); 
        }
     }
     public FragmentModel ParentFragment { get; set; }
     public List<FragmentModel> ChildFragments { get; set; }                   
     public event PropertyChangedEventHandler PropertyChanged;
     protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
     {
        if (PropertyChanged != null)
        {
            PropertyChanged?.Invoke(this, new 
            PropertyChangedEventArgs(propertyName));
        }
     }
}

Filling of NestingTree data from XML file:

XDocument xmlNestingTree = XDocument.Load("nesting_tree.xml");
if (xmlNestingTree.Element("NestingTree") is not null)
{
   int count = 0;
   foreach (XElement fragment in 
    xmlNestingTree.Element("NestingTree").Elements("fragment"))
   {
       string id = fragment.Attribute("id").Value;
       FragmentModel f = new FragmentModel
       {
           fragmentId = id,
           FragmentName = fragment.Attribute("name").Value,
       };
       nestingTree.Add(id, f);
   }
   foreach (XElement fragment in 
     xmlNestingTree.Element("NestingTree").Elements("fragment"))
   {
        FragmentModel currentFragment = nestingTree.Values.Where(f => f.fragmentId == fragment.Attribute("id").Value).FirstOrDefault();
        FragmentModel parentFragment = nestingTree.Values.Where(f => f.ChildFragments.Contains(currentFragment)).FirstOrDefault();
        currentFragment.ParentFragment = parentFragment; 
        if (Int32.TryParse(fragment.Element("childs").Attribute("count").Value, out count) && count > 0)
        {
            foreach (XElement child in fragment.Element("childs").Elements("child"))
            {
                FragmentModel currentChildFragment = nestingTree.Values.Where(f => f.fragmentId == child.Attribute("id").Value).FirstOrDefault();  
                currentFragment
                    .ChildFragments
                    .Add(currentChildFragment);
            }
        }
    }
    NestingTree = nestingTree;
}

Solution

  • Possible approaches of saving tree data are:

    • store linear list of items, where each item contains "parent_id" attribute
    • store list of children directly in each element.

    Your xml uses both approaches in the same time. I'd suggest to remove 'parent_id' (code will recursively read each xml element and build tree) or remove 'children' (in this case code will read all elements to list and build tree by levels, first search root fragment(s) with no parent, then loop by fond list and search fragments whose parent is current item, etc).

    Here is example of second approach: Read a XML tree structure recursively in a List<T> with children lists<T>