wpf 为数据网格行创建上下文菜单

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5200687/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 22:38:11  来源:igfitidea点击:

Create contextmenus for datagrid rows

wpfxamldatagridcontextmenu

提问by Jay

I have a datagrid that potentially can have many rows. As the user right clicks one of the rows, I need to show a context menu for each of the rows and perform an action (same action but different data item according to the current selected row) when the user clicks the option.

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

What is the best strategy for this?

什么是最好的策略?

I'm fearing that a ContextMenu for each row is overkill even though I'm creating the menu using the ContextMenuOpening event, sort of a "lazy load" for the context menu. Should I only use one ContextMenu for the datagrid? But with this I would have some more work regarding the click event, to determine the correct row, etc.

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

回答by vortexwolf

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 ContextMenufor a DataGrid.

据我所知,某些操作将根据行被禁用或启用,因此ContextMenu对于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}"/>

The DataGridmust have a binding to a list of view models with commands:

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

The context menu is created in the resources collection of the UserControland I think there is only one object which is connected with datagrid rows by reference, not by value.

上下文菜单是在资源集合中创建的UserControl,我认为只有一个对象通过引用而不是通过值与数据网格行连接。

Here is another example of ContextMenufor a Commandinside a MainViewModel. I suppose that DataGridhas a correct view model as the DataContext, also the CommandParameter attribute must be placed before the Command attribute:

这是ContextMenufor a Commandinside a 的另一个示例MainViewModel。我想它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>

Models:

楷模:

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

But there is a problem that MenuItemisn't displayed as a disabled item if CanExecutereturns false. The possible workaround is using a ParentModelproperty inside the ItemModel, but it doesn't differ much from the first solution. Here is example of above-described solution:

但是有一个问题,MenuItem如果CanExecute返回 false则不会显示为禁用项。可能的解决方法是ParentModel在 内部使用一个属性ItemModel,但它与第一​​个解决方案没有太大区别。以下是上述解决方案的示例:

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

And MenuItem in XAML will be simplier:

XAML 中的 MenuItem 会更简单:

<MenuItem Header="Edit" CommandParameter="{Binding}"
              Command="{Binding ParentViewModel.DataGridActionCommand}" />