【问题标题】:WPF context menu whose items are defined as data templatesWPF 上下文菜单,其项目被定义为数据模板
【发布时间】:2012-06-20 10:51:23
【问题描述】:

我有一个显示项目集合的列表视图,每个项目都有一个视图模型 (MVVM) 作为其基础数据。

当用户右键单击这些列表视图项之一时,我想做的是在上下文菜单中显示不同的菜单项。显示的菜单项取决于所选项目的类型(即底层视图模型的类型)。

我希望下面的内容可以正常工作,但事实并非如此(上下文菜单中不显示任何项目)。

<ListView.ContextMenu>
<ContextMenu DataContext="{Binding Path=PlacementTarget.SelectedItem, RelativeSource={RelativeSource Self}}">
    <ContextMenu.Resources>                        
        <DataTemplate DataType="{x:Type ViewModels:ViewModel1}">
            <MenuItem Header="DoStuffForVM1" Command="{Binding DoStuffForVM1Command}"/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type ViewModels:ViewModel2}">
            <MenuItem Header="DoStuffForVM2" Command="{Binding DoStuffForVM2Command}"/>
        </DataTemplate>
    </ContextMenu.Resources>
    <ContentPresenter ContentSource="{Binding}" />
</ContextMenu>
</ListView.ContextMenu>

有什么想法吗?

谢谢。

【问题讨论】:

  • 另外值得一提的是,我也没有遇到任何数据绑定错误。

标签: wpf binding mvvm contextmenu datatemplate


【解决方案1】:

这对我有用:

<ListView.ContextMenu>
<ContextMenu>
 <ContentPresenter Content="{Binding Path=PlacementTarget.SelectedItem, 
                             RelativeSource={RelativeSource AncestorType=ContextMenu}}" >
    <ContentPresenter.Resources>                        
        <DataTemplate DataType="{x:Type ViewModels:ViewModel1}">
            <MenuItem Header="DoStuffForVM1" Command="{Binding DoStuffForVM1Command}"/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type ViewModels:ViewModel2}">
            <MenuItem Header="DoStuffForVM2" Command="{Binding DoStuffForVM2Command}"/>
        </DataTemplate>
    </ContentPresenter.Resources>
  </ContentPresenter>
</ContextMenu>
</ListView.ContextMenu>

【讨论】:

    【解决方案2】:

    那是因为你设置的是ListView的ContextMenu,所以你的DataContext是ListView的外部上下文,而不是单个列表项的ViewModel。

    您需要改为设置每个项目的 ContextMenu。例如,使用样式:

    <ListView.Resources>
        <ContextMenu x:Key="ItemContextMenu">
          <MenuItem Header="DoStuffForVM1" Command="{Binding DataContext.DoStuffForVM1Command, RelativeSource={RelativeSource AncestorType={x:Type ListView}}"/>
        </ContextMenu>
    </ListView.Resources>
    <ListView.ItemContainerStyle>
        <Style TargetType="{x:Type ListViewItem}">
          <Setter Property="ContextMenu" Value="{StaticResource ItemContextMenu}"/>
        </Style>
    </ListView.ItemContainerStyle>
    

    但是,以上内容并未说明不同类型的菜单。

    如果要为每种类型的列表视图定义数据模板,最简单的方法是在每个 DataTemplate 中显式定义 ContextMenu

    如果没有,您将不得不使用样式中的触发器来完成。您可能必须编写一个转换器才能触发对象类型。

    【讨论】:

    • "如果您为每种类型的列表视图定义数据模板,最简单的方法是在每个 DataTemplate 中显式定义 ContextMenu。" - 我该怎么做?我确实为每种类型都有明确的数据模板,但是当我将上下文菜单添加到数据模板的根显示节点(在我的情况下为网格)时,菜单不会显示。
    • 这行不通。 ContextMenus 与应用程序的其余部分位于不同的 VisualTree 中,因此 MenuItem RelativeSource 绑定不起作用。
    • @RobJohnson:您需要在网格中设置 Border.Background=Transparent 以使上下文菜单出现在整个网格上。
    • @Rachel:Doh。你当然是对的。我之前已经通过使用外部上下文设置 ContextMenu 的标记来解决这个问题。 (ps。我可以说您的 WPF 答案在过去几个月里对我有很大帮助吗?谢谢。)
    • @GazTheDestroyer 谢谢! :) 关于 WPF,我还有很多东西要学,在 SO 上回答问题有助于我学习
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-22
    • 1970-01-01
    • 2014-10-09
    • 2016-11-21
    • 1970-01-01
    • 2014-02-25
    相关资源
    最近更新 更多