WPF 中的动态菜单

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19298992/
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-13 09:49:47  来源:igfitidea点击:

Dynamic menu in WPF

c#wpf

提问by Ejrr1085

How to add menu items to menu control (not contextmenu) in WPF from a database table with Bindings and Observable collections?. I have this menu:

如何从具有绑定和可观察集合的数据库表中将菜单项添加到 WPF 中的菜单控件(不是上下文菜单)?我有这个菜单:

<Menu HorizontalAlignment="Left" Height="27" VerticalAlignment="Top" Width="649">
    <MenuItem Header="_File">
       <MenuItem Header="_Exit" Command="{Binding ExitCommand}"/>
       </MenuItem>
    <MenuItem Header="_MyMenu">
       <MenuItem Header="_SubMenu1" Command="{Binding  SubMenu1Command}" />
       <MenuItem Header="_SubMenu2" Command="{Binding  SubMenu2Command}" />
    </MenuItem>
</Menu>

The "SubMenu1" and "_SuMenu2" are values from the database table:

“SubMenu1”和“_SuMenu2”是来自数据库表的值:

codSubMenu | SubMenuColum | CommandColumn

codSubMenu | 子菜单栏 | 命令列

1__________|SubMenu1_____|SubMenu1Command 2__________|SubMenu2_____|_SubMenu2Command

1_ ___ ___ ___| 子菜单1 ___ __| SubMenu1Command 2 ___ ___ ____| SubMenu2 _____|_SubMenu2Command

I need something this:

我需要这样的东西:

<Menu HorizontalAlignment="Left" Height="27" VerticalAlignment="Top" Width="649"
    ItemsSource="{Binding ObservableCollectionMenu}">
    <MenuItem Header="_File">
       <MenuItem Header="_Exit" Command="{Binding ExitCommand}"/>
    </MenuItem>
    <MenuItem Header="_MyMenu">
        <MenuItem Header="{Binding  ObservableCollectionMenu.SubMenuColumn}" Command="{Binding  ObservableCollectionMenu.CommandColumn}" />
    </MenuItem>
</Menu>

When I run the app the menu must show this when I press the options File and MyMenu:

当我运行应用程序时,菜单必须在我按下选项 File 和 MyMenu 时显示:

File | MyMenu

档案 | 我的菜单

Exit | SubMenu1

退出 | 子菜单1

___| SubMenu2

___| 子菜单2

回答by cguedel

Use the ItemsSourceproperty of the Menu and the MenuItems (in a style) to bind your collections:

使用ItemsSourceMenu 和 MenuItems的属性(在一个样式中)来绑定你的集合:

<Menu ItemsSource="{Binding YourCollection}" />

and

<Style TargetType="MenuItem">
    <Setter Property="Header" Value="{Binding Path=Name}" />
    <Setter Property="ItemsSource" Value="{Binding Path=Children}" />
</Style>

Edit: For command binding do the following:

编辑:对于命令绑定,请执行以下操作:

  1. Add a setter like this to the template of the MenuItem:

    <Setter Property="Command" Value="{Binding Path=Command}" />
    
  2. Use this structure for a MenuItemview model:

    public class BindableMenuItem
    {
         public string Name { get; set; }
         public BindableMenuItem[] Children { get; set; }
         public ICommand Command { get; set; }
    }
    
  3. Add the root items to a collection of BindableMenuItemsand bind this collection to the menu.

  1. 将这样的 setter 添加到 MenuItem 的模板中:

    <Setter Property="Command" Value="{Binding Path=Command}" />
    
  2. 将此结构用于MenuItem视图模型:

    public class BindableMenuItem
    {
         public string Name { get; set; }
         public BindableMenuItem[] Children { get; set; }
         public ICommand Command { get; set; }
    }
    
  3. 将根项添加到的集合BindableMenuItems并将此集合绑定到菜单。

回答by Adolfo Perez

This is how I solved it,

我是这样解决的

I created a MenuItem class (notice that it has a list of Items so you can build sub-menus):

我创建了一个 MenuItem 类(请注意,它有一个项目列表,因此您可以构建子菜单):

public class MenuItem : ModelBase<MenuItem>
{
    private List<MenuItem> _Items;

    public MenuItem(string header, ICommand command)
    {
        Header = header;
        Command = command;
    }

    public MenuItem()
    {

    }

    public string Header { get; set; }

    public List<IMenuItem> Items
    {
        get { return _Items ?? (_Items = new List<IMenuItem>()); }
        set { _Items = value; }
    }

    public ICommand Command { get; set; }
    public string CommandName { get; set; }
    public object Icon { get; set; }
    public bool IsCheckable { get; set; }
    private bool _IsChecked;
    public bool IsChecked
    {
        get { return _IsChecked; }
        set
        {
            _IsChecked = value;
            NotifyPropertyChanged(m=>m.IsChecked);
        }
    }

    public bool Visible { get; set; }
    public bool IsSeparator { get; set; }
    public string InputGestureText { get; set; }
    public string ToolTip { get; set; }
    public int MenuHierarchyID { get; set; }
    public int ParentMenuHierarchyID { get; set; }
    public string IconPath { get; set; }
    public bool IsAdminOnly { get; set; }
    public object Context { get; set; }
    public IMenuItem Parent { get; set; }
    public int int_Sequence { get; set; }
    public int int_KeyIndex { get; set; }
}

And a View:

和一个视图:

<Menu DockPanel.Dock="Top" ItemsSource="{Binding Path=MainMenu}">
    <Menu.ItemContainerStyle>
        <Style>
            <Setter Property="MenuItem.Header" Value="{Binding Path=Header}" />
            <Setter Property="MenuItem.ItemsSource" Value="{Binding Path=Items}" />
            <Setter Property="MenuItem.Icon" Value="{Binding Path=Icon}" />
            <Setter Property="MenuItem.IsCheckable" Value="{Binding Path=IsCheckable}" />
            <Setter Property="MenuItem.IsChecked" Value="{Binding Path=IsChecked,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
            <Setter Property="MenuItem.Command" Value="{Binding Path=Command}" />
            <!--<Setter Property="MenuItem.CommandParameter" Value="{Binding Path=IsChecked}"/>-->
            <Setter Property="MenuItem.CommandParameter" Value="{Binding Path=.}"/>
            <Setter Property="MenuItem.InputGestureText" Value="{Binding Path=InputGestureText}"/>
            <Setter Property="MenuItem.ToolTip" Value="{Binding Path=ToolTip}" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=IsSeparator}" Value="true">
                    <Setter Property="MenuItem.Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type MenuItem}">
                                <Separator Style="{DynamicResource {x:Static MenuItem.SeparatorStyleKey}}" />
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Menu.ItemContainerStyle>
</Menu>

Where MainMenuis an ObservableCollectionproperty in my main ViewModel, which you can populate from your database.

我的主 ViewModel 中MainMenuObservableCollection属性在哪里,您可以从数据库中填充该属性。

    public ObservableCollection<MenuItem> MainMenu
    {
        get { return _MainMenu; }
        set
        {
            _MainMenu = value;
            NotifyPropertyChanged(x => x.MainMenu);
        }
    }

回答by Ejrr1085

I don't have a quick solution in XAML. I needed get submenus items from database, according specific profiles, some users had all items others only 2 or 3 items. The unique way is create the menu in XAML with disabled items, pass the menu reference to ViewModel(if is MVVM App) and compare with the ObservableCollection, only the items equals are enabled:

我在 XAML 中没有快速解决方案。我需要从数据库中获取子菜单项,根据特定的配置文件,一些用户拥有所有项目,其他只有 2 或 3 个项目。独特的方法是在 XAML 中创建带有禁用项的菜单,将菜单引用传递给 ViewModel(如果是 MVVM 应用程序)并与 ObservableCollection 比较,仅启用项等于:

<menu horizontalalignment="Left" height="27" verticalalignment="Top" width="649" name="menu1">
      <menuitem header="_File">
          <menuitem header="_Exit" command="{Binding ExitCommand}" />
      </menuitem>
      <menuitem header="_MyMenu">
          <menuitem header="_SubMenu1" command="{Binding  Command1}" isenabled="False" />
          <menuitem header="_SubMenu2" command="{Binding  Command2}" isenabled="False" />
      </menuitem>
</menu>

ViewModel:

视图模型:

for (int i = 0; i < ObservableCollectionMenu.Count; i++)
{

    for (int j = 0; j < ((MenuItem)menu1.Items[1]).Items.Count; j++)
    {
         if (((MenuItem)((MenuItem)menu1.Items[1]).Items[j]).Header.ToString().Equals(ObservableCollectionMenu[i].SubMenuColumn))
         {
            ((MenuItem)((MenuItem)menu1.Items[1]).Items[j]).IsEnabled = true;
             break;
         }
    }
}

Thanks to all who answered my question, stackoverflow has better help that codeproject.

感谢所有回答我问题的人,stackoverflow 可以更好地帮助该代码项目。