To do what you want you can modify the ItemContainerStyle
of the TreeView
:
<TreeView>
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
Your view-model (the view-model for each item in the tree) then has to expose a boolean IsSelected
property.
If you want to be able to control if a particular TreeViewItem
is expanded you can use a setter for that property too:
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
Your view-model then has to expose a boolean IsExpanded
property.
Note that these properties work both ways so if the user selects a node in the tree the IsSelected
property of the view-model will be set to true. On the other hand if you set IsSelected
to true on a view-model the node in the tree for that view-model will be selected. And likewise with expanded.
If you don't have a view-model for each item in the tree, well, then you should get one. Not having a view-model means that you are using your model objects as view-models, but for this to work these objects require an IsSelected
property.
To expose an SelectedItem
property on your parent view-model (the one you bind to the TreeView
and that has a collection of child view-models) you can implement it like this:
public ChildViewModel SelectedItem {
get { return Items.FirstOrDefault(i => i.IsSelected); }
}
If you don't want to track selection on each individual item on the tree you can still use the SelectedItem
property on the TreeView
. However, to be able to do it "MVVM style" you need to use a Blend behavior (available as various NuGet packages - search for "blend interactivity").
Here I have added an EventTrigger
that will invoke a command each time the selected item changes in the tree:
<TreeView x:Name="treeView">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<i:InvokeCommandAction
Command="{Binding SetSelectedItemCommand}"
CommandParameter="{Binding SelectedItem, ElementName=treeView}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeView>
You will have to add a property SetSelectedItemCommand
on the DataContext
of the TreeView
returning an ICommand
. When the selected item of the tree view changes the Execute
method on the command is called with the selected item as the parameter. The easiest way to create a command is probably to use a DelegateCommand
(google it to get an implementation as it is not part of WPF).
A perhaps better alternative that allows two-way binding without the clunky command is to use BindableSelectedItemBehavior provided by Steve Greatrex here on Stack Overflow.