Search code examples
wpftreeview

WPF TreeView expand roots only


All root items in the TreeView should be expanded by default. Root items have a separate ViewModel from child items.

Treeview XAML:

<TreeView>
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type models:RootModel}" ItemsSource="{Binding Roots}">
            <TextBlock Text="{Binding Title}"/>
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate DataType="{x:Type models:Child1Model}" ItemsSource="{Binding Childs}">
            <TextBlock Text="{Binding Title}"/>
        </HierarchicalDataTemplate>
        <DataTemplate DataType="{x:Type models:Child2Model}">
            <TextBlock Text="{Binding Title}"/>
        </DataTemplate>
    </TreeView.Resources>
</TreeView>

The hierarchy is like so:

treeview item hierarchy

All items with the root viewmodel should be expanded while all child items are collapsed. How do I achieve this behavior? I am still very new to WPF so I didnt really know what to do, but I tried following things after some 'research':

Define a IsExpanded property in the view model: Obviously it wont be used.

private bool _isExpanded = true;
public bool IsExpanded
{
    get => _isExpanded;
    set
    {
        _isExpanded = value;
        OnPropertyChanged(nameof(IsExpanded)); //base.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Apply a style to the HierachicalDataTemplate: it doesnot support styling of the TreeViewItem itself, only the container.

<Style x:Key="RootItem" TargetType="TreeViewItem">
    <Style.Setters>
        <Setter Property="IsExpanded" Value="True"/>
    </Style.Setters>
</Style>
<HierarchicalDataTemplate DataType="{x:Type models:RootModel}" ItemsSource="{Binding Roots}" ItemContainerStyle="{StaticResource RootItem}">

I found an answer how to set expand all TreeViewItems but I have no way of modifying it to only affect one itemtype/viewmodel. https://stackoverflow.com/a/6952701/6401643

<TreeView>
    <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsExpanded" Value="True" />
        </Style>
    </TreeView.ItemContainerStyle>
</TreeView>

Any help is very much appreciated. Thanks in advance.


Solution

  • I had to bind the TreeViewItem property IsExpanded to my viewmodel via the above mentioned answer. In my viewmodel I defined the property IsExpanded:

    private bool _isExpanded = true;
    public bool IsExpanded
    {
        get => _isExpanded;
        set
        {
            _isExpanded = value;
            OnPropertyChanged(nameof(IsExpanded)); //base.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    

    And then two-way bound it to the TreeViewItem property:

    <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}">
        <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
        <Setter Property="FontWeight" Value="Normal" />
        <Style.Triggers>
            <Trigger Property="IsSelected" Value="True">
                <Setter Property="FontWeight" Value="Bold" />
            </Trigger>
        </Style.Triggers>
    </Style>
    </TreeView.ItemContainerStyle>
    

    Still; wired that it didnt work with the style I tried, since this effectively is the same.