C# 如何绑定列表视图项';s上下文菜单到ICommand

C# 如何绑定列表视图项';s上下文菜单到ICommand,c#,wpf,mvvm,C#,Wpf,Mvvm,我正在尝试将listview项的上下文菜单绑定到VM中包含的ICommand,但无法绑定它 我已尝试使用以下代码在listview项上显示上下文菜单,并将其绑定到我的VM 查看代码 <ListView ItemsSource="{Binding StudyList, Mode=TwoWay}" SelectedItem="{Binding SelectedStudy, Mode=TwoWay}" > <ListView.Resources> <

我正在尝试将listview项的上下文菜单绑定到VM中包含的ICommand,但无法绑定它

我已尝试使用以下代码在listview项上显示上下文菜单,并将其绑定到我的VM

查看代码

<ListView ItemsSource="{Binding StudyList, Mode=TwoWay}" SelectedItem="{Binding SelectedStudy, Mode=TwoWay}" >
    <ListView.Resources>
        <ContextMenu x:Key="ItemContextMenu" ItemsSource="{Binding StudyVM}">
            <MenuItem Header="Lock" Command="{Binding LockCommand}"/>
        </ContextMenu>
    </ListView.Resources>

    <ListView.ItemContainerStyle>
        <Style TargetType="{x:Type ListViewItem}">
            <Setter Property="ContextMenu" Value="{StaticResource ItemContextMenu}" />
        </Style>
    </ListView.ItemContainerStyle>

    <ListView.View>
        <GridView>
            <GridViewColumn Header="Status" DisplayMemberBinding="{Binding FullStatus}" Width="60"/>
            <GridViewColumn Header="Patient Name" DisplayMemberBinding="{Binding FullName}" Width="350"/>
        </GridView>
    </ListView.View>
</ListView>
public sealed class StudyVM : BaseVM {
   public RelayCommand LockCommand { get; set; }

   public StudyVM() {
       LockCommand = new RelayCommand(() => ExecuteLockCommad());
   }

   void ExecuteLockCommad() {
       //Some code to be execute when menu item clicked
   }
}
我已将视图的DataContext设置为StudyVM。请注意,我已经跳过了一些与列表视图项源和列表视图所选项相关的代码(这是离题的,可以正常工作)


“所有视图”部分工作正常,就像所有列表视图项都显示在列表中一样,单击列表项时上下文菜单显示。但唯一的问题是,当我们单击菜单项时,ExecuteLockCommad方法不会执行,即使我通过LockCommand将其绑定到上下文菜单项。

我尝试更改并进一步简化代码

main window.xaml

<Window x:Class="WpfApp5.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:WpfApp5"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>

    <Grid Margin="5,5,5,5">
        <ListView Name="lvSelectStudy"  >
            <!--ItemsSource="{Binding StudyList, Mode=TwoWay}" SelectedItem="{Binding SelectedStudy, Mode=TwoWay}"-->
            <ListView.Resources>
                <ContextMenu x:Key="ItemContextMenu">
                    <!--ItemsSource="{Binding StudyVM}"-->
                    <MenuItem Header="Lock" Command="{Binding LockCommand}"/>
                </ContextMenu>
            </ListView.Resources>

            <ListView.ItemContainerStyle>
                <Style TargetType="{x:Type ListViewItem}">
                    <Setter Property="ContextMenu" Value="{StaticResource ItemContextMenu}" />
                </Style>
            </ListView.ItemContainerStyle>
            <!--<ListView.View>
                <GridView>
                    <GridViewColumn Header="Status" DisplayMemberBinding="{Binding FullStatus}" Width="60"/>
                    <GridViewColumn Header="Patient Name" DisplayMemberBinding="{Binding FullName}" Width="350"/>
                </GridView>
            </ListView.View>-->
            <ListViewItem>Item1</ListViewItem>
            <ListViewItem>Item2</ListViewItem>
            <ListViewItem>Item3</ListViewItem>
            <ListViewItem>Item4</ListViewItem>
            <ListViewItem>Item5</ListViewItem>
        </ListView>
    </Grid>
</Window>
如果在
void ExecuteLockCommand()
中放置断点,则在右键单击ListViewItem后将调用该断点。。。
请注意,在您的代码中,此方法的名称与ViewModel的构造函数中定义的名称不同

您在代码中遇到的问题是
上下文菜单的
DataContext

当前的
ConextMenu
绑定将从当前上下文解析命令。由于
ContextMenu
是根据
ListViewItem
分配的,因此它的
DataContext
ListViewItem
是什么。在您的情况下,学习实体

然而,这不是一个主要问题,绑定可以指向其他上下文。在您的情况下,必须是
StudyVM
。由于这将是您的
列表视图的
DataContext
,因此我们可以通过此代码段将其指向:

Command="{Binding RelativeSource={RelativeSource AncestorType=ListView}, Path=DataContext.LockCommand}"  

另一种获取
DataContext
的方法可以通过
Name
完成。(我知道我问过你为什么要用它,这就是为什么)


...

这实现了相同的结果,但在WPF中使用名称有一个缺点(确切地说是x:Name)

问题在于上下文菜单不在可视化树中,因此基本上必须告诉上下文菜单要使用哪个数据上下文。您可以通过容器的tag属性传递datacontext,如下所示

<ListView Name="lvSelectStudy" Tag="{Binding DataContext, RelativeSource={RelativeSource Self}}">
    <ListView.Resources>
        <ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource {RelativeSource Self}}">                                
            <MenuItem Header="Lock" Command="{Binding LockCommand}"/>
        </ContextMenu>
    </ListView.Resources>
    ...
</ListView>

...

是否已检查Visual Studio中的输出窗口?检查绑定错误。还有,为什么您需要ListView的名称?ListView名称已被删除,因为它不是必需的。您是否检查了输出窗口?您还可以共享
RelayCommand
的实现吗?还有其他命令可以使用吗?@XAMlMAX,我按照您的建议设置了关联菜单的DataContext,它非常适合我。谢谢。关于不同的名字,这是打字错误,我已经相应地编辑了我的问题。对不起,我没有看到我的代码和你的编码建议之间有什么大的区别。我已根据您的建议更改了代码(删除了ContextMenu的ItemSource属性),但ExecuteLockCommand未执行(通过断点检查)。您是否使用GalaSoft的RelayCommand?我这么问是因为我和一个“自制”的社区有问题。。。
<ListView Name="ListView" ItemsSource="{Binding StudyList, Mode=TwoWay}" SelectedItem="{Binding SelectedStudy, Mode=TwoWay}">
    <ListView.Resources>
        <ContextMenu x:Key="ContextMenu">
            <MenuItem Header="Lock" Command="{Binding ElementName=ListView, Path=DataContext.LockCommand}"/>
        </ContextMenu>
    </ListView.Resources>
    ...
</ListView>  
<ListView Name="lvSelectStudy" Tag="{Binding DataContext, RelativeSource={RelativeSource Self}}">
    <ListView.Resources>
        <ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource {RelativeSource Self}}">                                
            <MenuItem Header="Lock" Command="{Binding LockCommand}"/>
        </ContextMenu>
    </ListView.Resources>
    ...
</ListView>