18

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

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

4

3 回答 3

13

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

希望它可以帮助遇到这个问题的人。

XAML

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

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

于 2014-04-24T18:56:45.643 回答
8

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

于 2013-02-09T02:18:44.153 回答
4

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

<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 中决定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
}
于 2013-02-09T02:04:03.770 回答