Kjara
Kjara

Reputation: 2902

Disable focusability of certain entries in TreeView

I have a TreeView that is filled with different types of items. The items can either be of type Node (then they may have children) or of type Entry (then they don't have children). For that, I bound my TreeView to my ViewModel property AllNodesAndEntries which is an ObservableCollection<object>. For different looks of Node and Entry I defined two DataTemplates. Here is the code:

<TreeView ItemsSource="{Binding AllNodesAndEntries}">
    <TreeView.Resources>
        <HierarchicalDataTemplate ItemsSource="{Binding Children}"
                                  DataType="{x:Type local:Node}">
            <TextBlock Text="{Binding Name}"
                       Background="LightBlue"/>
        </HierarchicalDataTemplate>
        <DataTemplate DataType="{x:Type local:Entry}">
            <TextBlock Text="{Binding Name}"
                       Background="LightSalmon"/>
        </DataTemplate>
    </TreeView.Resources>
</TreeView>

Now I want to make the Entry elements unfocusable if a certain condition is met (that is, if my ViewModel property MyProp is true).

So I added a trigger into the DataTemplate for Entry like this:

        <DataTemplate DataType="{x:Type local:Entry}">
            <TextBlock Text="{Binding Name}"
                       Background="LightSalmon"/>
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding MyProp}" Value="True">
                    <Setter Property="Focusable" Value="False"/>
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>

But it does not work, I can still select entries after MyProp was set to true. What am I doing wrong? How do I make it work?

I did put a NotifyPropertyChanged(nameof(MyProp)); in the setter of MyProp, so changes to MyProp will be reported to the View.

Upvotes: 5

Views: 735

Answers (3)

WPFGermany
WPFGermany

Reputation: 1649

It is no problem, you just need to set the Focusable property at the TreeViewItem. Just add the following to your TreeView.Resources:

<TreeView.Resources>
    <DataTemplate DataType="{x:Type local:Entry}">
        <TextBlock Text="{Binding Name}" Background="LightSalmon"/>
    </DataTemplate>
    <Style TargetType="TreeViewItem">
        <Style.Triggers>
            <DataTrigger Binding="{Binding MyProp}" Value="True">
                <Setter Property="Focusable" Value="False" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
</TreeView.Resources>

This style now occurs at all your TreeViewItems. If you like to prevent your Nodes from this style you could do it in code behind or just bind your item object and use a Converter.

Upvotes: 0

Funk
Funk

Reputation: 11211

Using the IsNodeConverter you've posted, you can implement a MultiDataTrigger that only fires when both conditions are fulfilled:

  • ViewModel MyProp = true
  • TreeViewItem of type Entry

XAML

<Window.Resources>
    <local:IsNodeConverter x:Key="IsNodeConverter"/>
</Window.Resources>

...

    <TreeView ItemsSource="{Binding AllNodesAndEntries}">
        <TreeView.Resources>

            ...

        </TreeView.Resources>
        <TreeView.ItemContainerStyle>
            <Style TargetType="{x:Type TreeViewItem}">
                <Style.Triggers>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition  Binding="{Binding DataContext.MyProp, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
                                        Value="True"/>
                            <Condition  Binding="{Binding Converter={StaticResource IsNodeConverter}}"
                                        Value="False"/>
                        </MultiDataTrigger.Conditions>
                        <MultiDataTrigger.Setters>
                            <Setter Property="Focusable" Value="False"></Setter>
                        </MultiDataTrigger.Setters>
                    </MultiDataTrigger>
                </Style.Triggers>
            </Style>
        </TreeView.ItemContainerStyle>
    </TreeView>

Upvotes: 5

R.Rusev
R.Rusev

Reputation: 1141

The problem is you set the Focusable Property to the DataTemplate which doesn't affect the selection of the TreeViewItem.

Instead you should set it on the TreeViewItem like this:

    <TreeView ItemsSource="{Binding Items}">
        <TreeView.ItemContainerStyle>
            <Style TargetType="{x:Type TreeViewItem}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding MyProp}"
                                 Value="True">
                        <Setter Property="Focusable"
                                Value="False" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TreeView.ItemContainerStyle>
    </TreeView>

Upvotes: 2

Related Questions