Reputation: 11
I have a TreeView
that's items are generated from HierarchicalDataTemplate
s. I need something to happen when each item is selected, and I just don't know how to do that the way it is right now.
<TreeView ItemsSource="{Binding Servers}" Width="250" Height="410">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type data:Server}" ItemsSource="{Binding Path=Children}">
<TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type data:Database}" ItemsSource="{Binding Path=Children}">
<TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type data:Table}" ItemsSource="{Binding Path=Children}">
<TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type data:Index}">
<TextBlock Text="{Binding Path=Name}"/>
</DataTemplate>
</TreeView.Resources>
</TreeView>
Upvotes: 0
Views: 42
Reputation: 22079
You can create a behavior that handles the SelectedItemChanged
event and exposes a dependency property for binding a command in a view model to be executed with the SelectedItem
.
public class SelectionChangedCommandBehavior : Behavior<TreeView>
{
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
nameof(Command), typeof(object), typeof(SelectionChangedCommandBehavior), new PropertyMetadata(null));
public ICommand Command
{
get => (ICommand)GetValue(CommandProperty);
set => SetValue(CommandProperty, value);
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.SelectedItemChanged += OnSelectedItemChanged;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.SelectedItemChanged -= OnSelectedItemChanged;
}
private void OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
var command = Command;
var selectedItem = AssociatedObject.SelectedItem;
if (command != null && command.CanExecute(selectedItem))
command.Execute(selectedItem);
}
}
You have to assign the behavior to your TreeView
and then bind the Command
property accordingly.
<TreeView ItemsSource="{Binding Servers}" Width="250" Height="410">
<i:Interaction.Behaviors>
<local:SelectionChangedCommandBehavior Command="{Binding SelectionChangedCommand}"/>
</i:Interaction.Behaviors>
</TreeView>
For the behavior you need to install the Microsoft.Xaml.Behaviors.Wpf
NuGet package to access the Behavior<T>
base class. Add this namespace in your XAML to use i:Interaction.Behaviors
.
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
Upvotes: 1
Reputation: 12276
If you bound isselected from the container to each viewmodel, you could act in the setter when the property changes to true.
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
You would need an isselected property in all your classes server, database etc. Put your logic in a method called from the property setter.
Upvotes: 0