WPF TreeView How to specify Multiple Properties of same type as sources of Child nodes

543 views Asked by At

I have a list of Rule class which needs to be bound to Treeview but hierarchy of Treeview nodes should be like this

IF
--IF2
--ElseIF
----IF3
--Else
----IF4

Here is the Rule class

public class Rule
{
    private List<RuleTag> elseIf = new List<RuleTag>();

    public RuleTag IF { get; set; }
    public RuleTag Else { get; set; }

    public List<RuleTag> ElseIf
    {
        get { return elseIf; }
    }

    public Rule() { }
}

And the RuleTag is defined below

public class RuleTag
{
    private List<Rule> children = new List<Rule>();

    public List<Rule> Children
    {
        get { return children; }
        set { children = value; }
    }

    public RuleTag() { }
}

In the example above IF2 is a member IF.Children, ElseIF is Rule.ElseIF[0] (If there are more than one ElseIf in array all need to be displayed) and IF3 is a member of Rule.ElseIf[0].Children and IF4 is a member of Rule.Else.Children

I've experimented with HierarchicalDataTemplate but I'm only able to bind to children of IF and unable to display Else and ElseIF as children

Here is my XAML

<TreeView.Resources>
    <HierarchicalDataTemplate DataType="{x:Type TangoRules:Rule}" ItemsSource="{Binding IF.Children}">
        <TextBlock Text="IF" />
    </HierarchicalDataTemplate>
</TreeView.Resources>
2

There are 2 answers

0
phantom On BEST ANSWER

I solved it using CompositeCollection by modifying the Rule class like below

public class Rule : INotifyPropertyChanged
{
    private ObservableCollection<RuleTag> elseIf = new ObservableCollection<RuleTag>();
    private RuleTag _else;
    private CompositeCollection children = new CompositeCollection();

    public RuleTag IF { get; set; }
    public RuleTag Else
    {
        get { return _else; }
        set
        {
            _else = value;
            OnPropertyChanged("Children");
        }
    }

    public ObservableCollection<RuleTag> ElseIf
    {
        get { return elseIf; }
    }

    public CompositeCollection Children
    {
        get
        {
            children.Clear();
            children.Add(new CollectionContainer() { Collection = IF.Children });
            children.Add(new CollectionContainer() { Collection = ElseIf });
            if (Else != null)
                children.Add(Else);
            return children;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}

Note that I've now also implemented the INotifyPropertyChanged interface that is because the else part in class wasn't a collection. Now when Rule class was instantiated if Else was empty it wasn't added to the CompositeCollection but if it's set later on, I would notify all the observers of CompositeCollection that this property is changed. Besides I've made all my lists e.g. IF.Childre, List observablecollection

1
ReeganLourduraj On

Try Hierarchical Datatemplate with two levels as:

<HierarchicalDataTemplate ItemsSource="{Binding RuleCollection}">
            <TextBlock Text="{Binding IF}" />                       
            <HierarchicalDataTemplate.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                    <HierarchicalDataTemplate.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding}" />
                        </DataTemplate>
                    </HierarchicalDataTemplate.ItemTemplate>                   
                </HierarchicalDataTemplate>
            </HierarchicalDataTemplate.ItemTemplate>

        </HierarchicalDataTemplate>