我试图将listview项的上下文菜单绑定到我的VM中包含的ICommand,但是无法绑定它。
我尝试了以下代码以在列表视图项上显示上下文菜单,并将其绑定到我的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>
VM代码
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。请注意,我已经跳过了一些与列表视图项源和列表视图所选项有关的代码(不在主题范围内并且工作正常)。
所有视图部分都可以正常工作,就像所有列表视图项都显示在列表中一样,当我们单击列表项时,上下文菜单会显示出来。但是唯一的问题是,即使我通过LockCommand将其绑定到上下文菜单项,单击菜单项时ExecuteLockCommad方法也不会执行。
答案 0 :(得分:2)
您的代码遇到的问题是DataContext
中的ContextMenu
。
您当前的ConextMenu
绑定将从当前上下文中解析命令。由于ContextMenu
是按ListViewItem
分配的,因此DataContext
就是ListViewItem
的内容。就您而言,StudyEntity
。
但是,这不是主要问题,绑定可以指向其他上下文。在您的情况下,该值必须为StudyVM
。因为这就是您DataContext
中的ListView
,所以我们可以通过以下代码段将其指向:
Command="{Binding RelativeSource={RelativeSource AncestorType=ListView}, Path=DataContext.LockCommand}"
Article from MSDN about RelativeSource MarkupExtension
获取DataContext
的另一种方法可以通过Name
完成。 (我知道我问过你为什么要使用它,这就是为什么)
<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>
这可以达到相同的结果,但是在WPF中使用名称有一个缺点(确切地说是x:Name)。 Article about memory leak。
答案 1 :(得分:0)
我尝试更改并进一步简化您的代码...
MainWindow.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>
MainWindowViewModel.cs
using GalaSoft.MvvmLight.Command;
namespace WpfApp5
{
public sealed class MainWindowViewModel : ViewModelBase
{
public RelayCommand LockCommand { get; set; }
public MainWindowViewModel()
{
LockCommand = new RelayCommand(() => ExecuteLockCommand());
}
void ExecuteLockCommand()
{
//Some code to be execute when menu item clicked
}
}
}
如果在void ExecuteLockCommand()
中放置一个断点,则在右键单击ListViewItem后会调用该断点...
请注意,在您的代码中,此方法的名称与ViewModel的构造函数中定义的名称不同。
答案 2 :(得分:0)
问题在于ContextMenu不在视觉树中,因此您基本上必须告诉Context菜单要使用的数据上下文。您可以如下所示通过容器的tag属性传递数据上下文。
<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>