WPF:如何动态生成ContextMenu

时间:2013-02-09 01:27:00

标签: wpf contextmenu

我有ListBox(带SelectionMode = Extended),它有多个项目,我想添加上下文菜单功能。问题是如何根据某些条件动态创建上下文菜单。例如。如果只选择了一个项目,我想显示常规上下文菜单,但是当选择多个项目时,显示其他上下文菜单(例如,添加了一些新项目)。另外,如果所选项目中至少有一个具有一些属性集,我想创建第三种上下文菜单。等等......可能有多种这样的条件。

基本上我需要在用户右键单击鼠标按钮之后立即动态生成上下文菜单,但在菜单实际显示之前。这可能吗?

3 个答案:

答案 0 :(得分:11)

我知道这是一个老问题。 似乎有一个非常简单的答案可以解决MVVM场景中OP的原始问题,因为ContextMenu类支持通过ItemsSource属性进行绑定。

希望它有助于遇到这种情况的人。

<强> XAML

      <ContextMenu ItemsSource="{Binding Path=ItemList, UpdateSourceTrigger=PropertyChanged}">
      </ContextMenu>

在ViewModel中,您可以修改&#34; ItemList&#34;属性根据当前的应用程序状态动态。

答案 1 :(得分:7)

我找到了问题的答案,它是ContextMenuOpening事件。 基本上我需要处理此事件并根据当前应用程序状态进行菜单调整。更多详情:https://msdn.microsoft.com/en-us/library/Bb613568(v=vs.100).aspx

答案 2 :(得分:3)

如果您要根据特定方案使用一组预定义的上下文菜单,则始终可以将上下文菜单创建为资源。

<Window.Resources>
    <ContextMenu x:Key="Menu1">
        <MenuItem>Item1</MenuItem>
    </ContextMenu>
    <ContextMenu x:Key="Menu2">
        <MenuItem>Item1</MenuItem>
        <MenuItem>Item2</MenuItem>
    </ContextMenu>
</Window.Resources>

然后在ListBox上创建数据触发器以设置要使用的ContextMenu,而不是我在下面所做的,我建议绑定到视图模型上的属性或后面的代码,因为它可能会在xaml中变得非常混乱。 此处的实现检查是否只选择了一个项目,在这种情况下切换到Menu1

<ListBox x:Name="mylist" SelectionMode="Multiple" ContextMenu="{StaticResource Menu2}" >
    <ListBox.Style>
        <Style TargetType="{x:Type ListBox}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=SelectedItems.Count, RelativeSource={RelativeSource Self}}" Value="1" >
                    <Setter Property="ContextMenu" Value="{StaticResource ResourceKey=Menu1}" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ListBox.Style>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=DisplayName}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

如果要显示的上下文菜单的选择仅与视图有关,我建议在后面的代码中处理它。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        // Hook up any events that might influence which menu to show
        mylist.SelectionChanged += listSelectionChanged;
        InitializeComponent();
    }

    private void listSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var listBox = sender as ListBox;
        if (listBox == null)
            return; // Or throw something, hard

        ContextMenu menuToUse;
        // Logic for selecting which menu to use goes here

        listBox.ContextMenu = menuToUse;
    }
}

如果ViewModel确实对要显示的菜单感兴趣(听起来不像它,但在不知道完整上下文的情况下很难分辨),那么你可以公开一些属性,让你在ViewModel中决定{{1 }} 显示。虽然不是单独的布尔属性,但您最有可能想要创建一个类,以确保在任何给定时间只有一个布尔值为真。

ContextMenu