MVVM中的上下文菜单

11

我想将上下文菜单绑定到一组命令。

<Grid.ContextMenu>
    <ContextMenu ItemsSource="{Binding ItemContextCommands, Converter={StaticResource commandToStringConverter}}">
            <ContextMenu.ItemTemplate >
                    <DataTemplate DataType="MenuItem">
                            <MenuItem Command="{Binding}"></MenuItem>
                        </DataTemplate>
                </ContextMenu.ItemTemplate>
        </ContextMenu>
</Grid.ContextMenu>

commandToStringConverter 的作用是将命令列表转换为字符串列表,对于列表中的每个命令都会调用其 ToString() 方法。

如何使每个 MenuItem 中的 Command 被调用?


你可能应该考虑使用另一个转换器,将每个{Binding}转换为实际的命令调用。 - Tigran
转换器返回一个Func列表?的列表。 - Mare Infinitus
3个回答

20

我会使用一个小的“视图模型”来保存这个命令所需的信息。

class ContextAction : INotifyPropertyChanged
{
    public string Name;
    public ICommand Action;
    public Brush Icon;
}

在您的视图模型中创建一个集合,该集合应获取上下文操作,例如

ObservableCollection<ContextAction> Actions {get;set;}

只需将此集合绑定到您的ContextMenu即可。

<Grid.ContextMenu>
    <ContextMenu ItemsSource="{Binding Actions}" />

ItemTemplate现在可以访问上下文菜单项的名称、命令和其他可能需要的内容。更改CommandParameter也可能很有用,这样它将使用操作所拥有的元素而不是操作本身来调用命令。


有人知道如何处理带有分隔符和子菜单的上下文菜单吗?这个解决方案似乎只适用于同类对象。 - Quark Soup
子菜单同样容易。只需为ContextMenu设置一个ItemContainerStyle,其中包含一个ItemsSource的setter,并将其绑定到ContextAction中类型为ObservableCollection<ContextAction>的新属性。对于分隔线,请参见解决方案。 - dowhilefor

15

我使用类似这样的内容:

public class ContextMenuVM
{ 
    public string Displayname {get;set;}
    public ICommand MyContextMenuCommand {get;set;}
}

在您的上下文菜单数据上下文中:

public ObservableCollection<ContextMenuVM> MyCommandList {get;set;}

在你的 XAML 中

<ContextMenu ItemsSource="{Binding MyCommandList}">
        <ContextMenu.ItemTemplate >
                <DataTemplate DataType="MenuItem">
                        <MenuItem Header="{Binding Displayname}" Command="{Binding MyContextMenuCommand}"></MenuItem>
                    </DataTemplate>
            </ContextMenu.ItemTemplate>
    </ContextMenu>

它没有使用IDE编写,因此可能存在一些语法错误。


6
这个解决方案对 MenuItem 进行了嵌套控制。 - Ole K

7

下面是一个改进的XAML版本,基于@blindmils的解决方案:

<ContextMenu ItemsSource="{Binding MyCommandList}">
    <ContextMenu.ItemContainerStyle>
        <Style TargetType="MenuItem">
            <Setter Property="Header" Value="{Binding Displayname}" />
            <Setter Property="Command" Value="{Binding MyContextMenuCommand }" />
        </Style>
    </ContextMenu.ItemContainerStyle>
</ContextMenu>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接