I have a TreeView with an ItemTemplate/HierarchicalDataTemplate. When I expand a TreeViewItem, I want to trigger a MessageBox. The issue I am currently experiencing is that despite the breakpoint being hit on the RelayCommand()
in the ViewModel, the actual MessageBox does not execute.
I tried moving the command inside the KeyViewModel itself, and the same behavior occurred.
XAML:
<Window x:Class="TreeViewProblem.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TreeViewProblem"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<TreeView Grid.Row="1" Grid.Column="0" Name="RegistryTreeView" ItemsSource="{Binding Keys}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding SubKeys}">
<TreeViewItem Header="{Binding name}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Expanded">
<i:InvokeCommandAction Command="{Binding ElementName=RegistryTreeView, Path=DataContext.TreeViewItemExpanded}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeViewItem>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</Window>
First of all you have set the breakpoint in the getter of the property. The MessageBox.Show
method is called when the command executes. It's not called when the InvokeCommandAction
binds to the property itself.
Second, the HierarchicalDataTemplate
is not supposed to contain a TreeViewItem
. The control creates its own TreeViewItem
containers and the Expanded
event of the one in your template is never fired.
Using an EventTrigger
won't work here unless you define a (complete) custom template for the TreeView
.
Instead you could define an ItemContainerStyle
and invoke the command programmatically:
public partial class MainWindow : Window
{
private readonly MainWindowViewModel _viewModel = new MainWindowViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = _viewModel;
}
private void TreeViewItem_Expanded(object sender, RoutedEventArgs e) =>
_viewModel.TreeViewItemExpanded.Execute(null);
}
XAML:
<TreeView Grid.Row="1" Grid.Column="0" Name="RegistryTreeView" ItemsSource="{Binding Keys}">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<EventSetter Event="Expanded" Handler="TreeViewItem_Expanded" />
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding SubKeys}">
<TextBlock Text="{Binding name}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
And no, this does not break the MVVM pattern as you invoke the very same command from the very same view. MVVM is not about eliminating code. It's about separation of concerns. Whether you invoke the view model command from the code-behind of the view or using an EventTrigger
and an InvokeCommandAction
from the XAML markup of the very same view doesn't matter as far as the pattern is concerned.