为datagrid行创建上下文菜单

时间:2011-03-05 00:18:38

标签: wpf xaml datagrid contextmenu

我有一个可能有很多行的数据网格。当用户右键单击其中一行时,我需要显示每个行的上下文菜单,并在用户单击选项时执行操作(根据当前所选行执行相同操作但不同的数据项)。

最佳策略是什么?

我担心每行的ContextMenu都是矫枉过正,即使我使用ContextMenuOpening事件创建菜单,也就是上下文菜单的“延迟加载”。我应该只为数据网格使用一个ContextMenu吗?但是有了这个,我会对click事件有更多的工作,以确定正确的行等。

1 个答案:

答案 0 :(得分:34)

据我所知,某些操作将会被禁用或启用,具体取决于行,因此ContextMenu的单DataGrid内没有任何意义。

我有一个行级上下文菜单的例子。

<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的资源集合中创建的,我认为只有一个对象通过引用与datagrid行连接,而不是通过值。

以下是ContextMenuCommand的{​​{1}}的另一个示例。我认为MainViewModel具有正确的视图模型DataGrid,CommandParameter属性也必须放在Command属性之前:

DataContext

型号:

    <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; } } 返回false,则存在MenuItem未显示为已禁用项的问题。可能的解决方法是在CanExecute内使用ParentModel属性,但与第一个解决方案没有太大区别。 以下是上述解决方案的示例:

ItemModel

XAML中的MenuItem将更简单:

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()};