wpfmvvmstylestreeviewitemitemcontainerstyle

WPF: Setting a binding for all TreeViewItem instance


Greetings,

I'm using WPF with a Model-View-ViewModel pattern, and I have a view model with an IsSelected property which I want to bind to a TreeViewItem's IsSelected property for all TreeViewItems in the scope. I'm attempting to do this with a Style and a Setter. This works apparently for the root-level TreeViewItems, but not for their children. Why is this? How can I have this apply to all TreeViewItem controls?

Here is the view XAML:

<UserControl x:Class="MyApp.AllAreasView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:MyApp="clr-namespace:MyApp"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="700">
<UserControl.Resources>
    <Style TargetType="{x:Type TreeViewItem}">
        <Setter Property="IsSelected"
                Value="{Binding IsSelected, Mode=TwoWay}"/>
    </Style>

    <MyApp:CountVisibilityConverter x:Key="CountVisibilityConverter" />

    <HierarchicalDataTemplate x:Key="AreaTemplate"
                              DataType="AreaViewModel"
                              ItemsSource="{Binding Path=SubareasCollectionView}">
        <WrapPanel>
            <TextBlock Text="{Binding Path=Name}" Margin="0 0 8 0" />
            <TextBlock DataContext="{Binding Path=Subareas}" 
                       Text="{Binding Path=Count, StringFormat= (\{0\})}"
                       Visibility="{Binding Path=Count, Converter={StaticResource CountVisibilityConverter}}" />
        </WrapPanel>
    </HierarchicalDataTemplate>
</UserControl.Resources>

<TreeView ItemsSource="{Binding TopLevelAreas}"
          ItemTemplate="{StaticResource AreaTemplate}">
</TreeView>

</UserControl>

Solution

  • I think we'll need more info to answer your question. Specifically, what your view model(s) look like. Below is an example you can copy and paste that works fine.

    Window1.xaml:

    <Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="Window1" Height="300" Width="300">
        <Window.Resources>
            <Style TargetType="{x:Type TreeViewItem}">
                <Setter Property="Background" Value="{Binding Background}"/>
            </Style>
    
            <HierarchicalDataTemplate x:Key="ItemTemplate" DataType="local:DataItem" ItemsSource="{Binding Path=Children}">
                <TextBlock Text="{Binding Name}" />
            </HierarchicalDataTemplate>
        </Window.Resources>
    
        <TreeView ItemsSource="{Binding}" ItemTemplate="{StaticResource ItemTemplate}"/>
    </Window>
    

    Window1.xaml.cs:

    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Windows;
    using System.Windows.Media;
    
    namespace WpfApplication1
    {
        public partial class Window1 : Window
        {
            public Window1()
            {
                InitializeComponent();
    
                var dis = new ObservableCollection<DataItem>();
                var di = new DataItem() { Name = "Top", Background = Brushes.Red };
                di.Children.Add(new DataItem() { Name = "Second", Background = Brushes.Blue });
    
                dis.Add(di);
                DataContext = dis;
            }
        }
    
        public class DataItem
        {
            public DataItem()
            {
                Children = new ObservableCollection<DataItem>();
            }
    
            public string Name
            {
                get;
                set;
            }
    
            public ICollection<DataItem> Children
            {
                get;
                set;
            }
    
            public Brush Background
            {
                get;
                set;
            }
        }
    }