WPF:如何动态生成ContextMenu

mat*_*i82 13 wpf contextmenu

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

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

nep*_*dev 13

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

希望它可以帮助有人遇到这个.

XAML

      <ContextMenu ItemsSource="{Binding Path=ItemList, UpdateSourceTrigger=PropertyChanged}">
      </ContextMenu>
Run Code Online (Sandbox Code Playgroud)

在ViewModel中,您可以根据当前应用程序状态动态修改"ItemList"属性.

  • 你如何处理菜单项上的绑定命令? (7认同)
  • @Julien,请参见[this](http://stackoverflow.com/a/22849063/1997232)答案。 (2认同)

mat*_*i82 7

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

  • 万一文档再次以任何方式被删除,标题为“如何:处理ContextMenuOpening事件”,因此您可以搜索它。 (2认同)

Pet*_*son 5

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

<Window.Resources>
    <ContextMenu x:Key="Menu1">
        <MenuItem>Item1</MenuItem>
    </ContextMenu>
    <ContextMenu x:Key="Menu2">
        <MenuItem>Item1</MenuItem>
        <MenuItem>Item2</MenuItem>
    </ContextMenu>
</Window.Resources>
Run Code Online (Sandbox Code Playgroud)

然后在你的数据触发器上创建数据触发器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>
Run Code Online (Sandbox Code Playgroud)

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

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果 ViewModel 确实对显示哪个菜单感兴趣(听起来不像,但在不了解完整上下文的情况下很难判断),您可以公开一些属性,让您决定在 ViewModel 中ContextMenu显示哪个菜单。尽管您最可能想要创建一个类,而不是单个布尔属性,以确保在任何给定时间只有一个布尔值为真。

public class MyViewModel : INotifyPropertyChanged
{

    public MyViewModel()
    {
        SelectedItems = new ObservableCollection<string>();
        SelectedItems.CollectionChanged += SelectedItemsChanged;
    }

    private void SelectedItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        // Logic to see which ShowMenuX property to set to true goes here
    }

    public ObservableCollection<string> SelectedItems { get; set; }

    private bool _showMenu1 = false;
    public bool ShowMenu1
    {
        get { return _showMenu1; }
        set
        {
            _showMenu1 = value;
            RaisePropertyChanged("ShowMenu1");
        }
    }

    // INotifyPropertyChanged implementation goes here
}
Run Code Online (Sandbox Code Playgroud)