使用多个模板时,将命令绑定到 `ContextMenu` 中的 `DataTemplate`?

Bind command to `DataTemplate` in `ContextMenu` when using multiple templates?

我正在尝试提供具有不同外观和功能的上下文菜单项,但我找不到将命令绑定到这些项的方法。每个菜单项的视图模型都派生自一个 class AbstractEntryViewModel。这是我当前项目结构的一个简短示例。使用 ContextMenu.Resources 是我发现将模板绑定到特定类型的唯一方法。

<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

通常我可以像这样将命令绑定到 MenuItem

<MenuItem Command="{Binding StaticResourceOrViewModelProperty}" />

如何使用数据模板做同样的事情?是否有一个不可见的容器,一个数据模板内容的包装器,我可以用它来绑定命令?

为简单起见,假设有 2 个派生的 ViewModel,VM1VM2,分别有一个 Command Command1 和一个 Command2

两步:

1) 在基础ViewModel中定义这个属性:

public Type Type
{
    get { return GetType(); }
}

我们不能直接使用 GetType(),我们需要包装 属性 因为 WPF Bindings 只能使用属性。

2) 使用此 属性 在 Style 上为 ContextMenu MenuItem:

设置一个 DataTrigger
<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>

DataTemplates 与您一样设置,其中:

<DataTemplate DataType="{x:Type local:VM1}">
  <!-- Content -->
</DataTemplate>
<DataTemplate DataType="{x:Type local:VM2}">
  <!-- Content -->
</DataTemplate>