更新时间:2023-11-30 22:11:40
据我所知,有些动作会根据行被禁用或启用,所以在单个 ContextMenu
用于 DataGrid
.
As far as I know, some of the actions will be disabled or enabled depending on the row, so there is no point in a single ContextMenu
for a DataGrid
.
我有一个行级上下文菜单的示例.
I have an example of the row-level context menu.
<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
必须使用命令绑定到视图模型列表:
The DataGrid
must have a binding to a list of view models with commands:
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
的资源集合中创建的,我认为只有一个对象通过引用而不是通过值与数据网格行连接.
The context menu is created in the resources collection of the UserControl
and I think there is only one object which is connected with datagrid rows by reference, not by value.
这是 MainViewModel
中 Command
的另一个 ContextMenu
示例.我想 DataGrid
有一个正确的视图模型作为 DataContext
,CommandParameter 属性也必须放在 Command 属性之前:
Here is another example of ContextMenu
for a Command
inside a MainViewModel
. I suppose that DataGrid
has a correct view model as the DataContext
, also the CommandParameter attribute must be placed before the Command attribute:
<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
属性,但它与第一个解决方案没有太大区别.以下是上述解决方案的示例:
But there is a problem that MenuItem
isn't displayed as a disabled item if CanExecute
returns false. The possible workaround is using a ParentModel
property inside the ItemModel
, but it doesn't differ much from the first solution.
Here is example of above-described solution:
public class ItemModel
{
public int Id { get; set; }
public string Title { get; set; }
public MainViewModel ParentViewModel { get; set; }
}
//Somewhere in the code-behind, create the main view model
//and force child items to use this model as a parent model
var mainModel = new MainViewModel { Items = items.Select(item => new ItemViewModel(item, mainModel)).ToList()};
XAML 中的 MenuItem 会更简单:
And MenuItem in XAML will be simplier:
<MenuItem Header="Edit" CommandParameter="{Binding}"
Command="{Binding ParentViewModel.DataGridActionCommand}" />