据我所知,一些操作会因行而异,因此为
DataGrid
设计单个
ContextMenu
没有意义。
我有一个基于行的上下文菜单示例。
<UserControl.Resources>
<ContextMenu x:Key="RowMenu" DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Edit" Command="{Binding EditCommand}"/>
</ContextMenu>
<Style x:Key="DefaultRowStyle" TargetType="{x:Type DataGridRow}">
<Setter Property="ContextMenu" Value="{StaticResource RowMenu}" />
</Style>
</UserControl.Resources>
<DataGrid RowStyle="{StaticResource DefaultRowStyle}"/>
DataGrid
必须绑定到一个带有命令的视图模型列表:
public class ItemModel
{
public ItemModel()
{
this.EditCommand = new SimpleCommand
{
ExecuteDelegate = _ => MessageBox.Show("Execute"),
CanExecuteDelegate = _ => this.Id == 1
};
}
public int Id { get; set; }
public string Title { get; set; }
public ICommand EditCommand { get; set; }
}
上下文菜单是在UserControl
的资源集合中创建的,我认为只有一个对象通过引用而不是值连接到数据格行。
这是另一个关于MainViewModel
中Command
的ContextMenu
的例子。我假设DataGrid
具有正确的视图模型作为DataContext
,并且CommandParameter
属性必须放置在Command
属性之前:
<ContextMenu x:Key="RowMenu" DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Edit" CommandParameter="{Binding}"
Command="{Binding DataContext.DataGridActionCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}" />
</ContextMenu>
模型:
public class MainViewModel
{
public MainViewModel()
{
this.DataGridActionCommand = new DelegateCommand<ItemModel>(m => MessageBox.Show(m.Title), m => m != null && m.Id != 2);
}
public DelegateCommand<ItemModel> DataGridActionCommand { get; set; }
public List<ItemModel> Items { get; set; }
}
public class ItemModel
{
public int Id { get; set; }
public string Title { get; set; }
}
但是有一个问题,如果CanExecute
返回false,则MenuItem
不会显示为禁用项。可能的解决方法是在ItemModel
内部使用ParentModel
属性,但它与第一种解决方案并没有太大区别。
以下是上述解决方案的示例:
public class ItemModel
{
public int Id { get; set; }
public string Title { get; set; }
public MainViewModel ParentViewModel { get; set; }
}
var mainModel = new MainViewModel { Items = items.Select(item => new ItemViewModel(item, mainModel)).ToList()};
在XAML中,MenuItem会更简单:
<MenuItem Header="Edit" CommandParameter="{Binding}"
Command="{Binding ParentViewModel.DataGridActionCommand}" />