Reputation: 1951
I'm trying to give a context menu items with different look and functionality, but I cannot find a way to bind commands to these items. Each menu item's view model is derived from one class AbstractEntryViewModel
. Here is a shortened example of my current project's structure. Using ContextMenu.Resources
is the only way I found to bind a template to a certain type.
<ContextMenu ItemsSource="{Binding Entries}">
<ContextMenu.Resources>
<DataTemplate DataType="{x:Type local:NopEntryViewModel}">
<!-- Content -->
</DataTemplate>
<HierarchicalDataTemplate
DataType="{x:Type local:GroupEntryViewModel}"
ItemsSource="{Binding Entries}">
<!-- Content -->
</HierarchicalDataTemplate>
<!-- More templates -->
</ContextMenu.Resources>
</ContextMenu>
internal abstract AbstractEntryViewModel : INotifyPropertyChanged {
public abstract void Invoke ();
// ...
}
internal NopEntryViewModel : AbstractEntryViewModel {
public override void Invoke () {}
}
internal GroupEntryViewModel : AbstractEntryViewModel {
public override void Invoke () { /* ... */ }
// ...
}
// More view models
Normally I can bind a command to a MenuItem
like so
<MenuItem Command="{Binding StaticResourceOrViewModelProperty}" />
How can I do the same thing with data templates? Is there an invisible container, a wrapper for the data template's content, that I can use to bind a command to?
Upvotes: 1
Views: 476
Reputation: 3833
For simplicity, suppose 2 derived ViewModels, VM1
and VM2
, with respectively a Command
Command1
and a Command2
.
Two steps:
1) Define in the base ViewModel
this property:
public Type Type
{
get { return GetType(); }
}
We cannot use GetType()
directly, we need a wrapping property since WPF Bindings
work only with properties.
2) Use this property to set a DataTrigger
on the Style
for the ContextMenu
MenuItem
:
<ContextMenu.Resources>
<Style TargetType="{x:Type MenuItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding Type}" Value="{x:Type local:VM1}">
<Setter Property="Command" Value="{Binding Command1}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Type}" Value="{x:Type local:VM2}">
<Setter Property="Command" Value="{Binding Command2}"/>
</DataTrigger>
<!-- add other DataTriggers, one for every ViewModel -->
</Style.Triggers>
</Style>
</ContextMenu.Resources>
The DataTemplates
are set as you do, with:
<DataTemplate DataType="{x:Type local:VM1}">
<!-- Content -->
</DataTemplate>
<DataTemplate DataType="{x:Type local:VM2}">
<!-- Content -->
</DataTemplate>
Upvotes: 2