【问题标题】:How to fill a MenuItem dynamically during runtime with MenuItems?如何在运行时使用 MenuItems 动态填充 MenuItem?
【发布时间】:2020-03-11 11:49:07
【问题描述】:

我有以下(简化的)视图模型:

public class ViewModel
{
    ObservableCollection<RackViewModel> Racks { get; set; }
}

public class RackViewModel
{
    public string Header { get; set; }

    public ICommand ActivateCommand { get; }

    public ICommand ShowInfoCommand { get; }
}

viewmodel 类当然实现了INotifyPropertyChanged,为简洁起见,我省略了它。我想在窗口的菜单栏中显示机架。我试过这样:

<Menu DockPanel.Dock="Top">
<MenuItem Header="Racks">
                <ItemsControl ItemsSource="{Binding Racks}">
                    <ItemsControl.ItemTemplate>
                        <ItemContainerTemplate>
                            <MenuItem Header="{Binding Header}">
                                <MenuItem Command="{Binding ActivateCommand}" Header="Activate"/>
                                <MenuItem Command="{Binding ShowInfoCommand}" Header="Show Information"/>
                            </MenuItem>
                        </ItemContainerTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </MenuItem>
</Menu>

这给了我以下结果:

当我将鼠标悬停在菜单上时,所有项目都被同时标记,我无法访问子菜单。我希望它是以下内容:

有谁知道我做错了什么?

【问题讨论】:

  • 您的问题是RackViewModel 类不是分层的。
  • @mm8:感谢您的评论。你能告诉我更多关于如何使RackViewModel分层的信息吗?
  • 向其添加IEnumerable&lt;RackViewModel&gt; 属性。

标签: c# wpf mvvm menuitem


【解决方案1】:

您可以使用ItemSource 属性

看起来像:

    <Menu>
        <MenuItem Header="Click me" Command="{Binding ChangeCommand}"></MenuItem>
        <MenuItem Header="Items" ItemsSource="{Binding Items}">
            <MenuItem.ItemContainerStyle>
                <Style TargetType="{x:Type MenuItem}">
                    <Setter Property="Header" Value="{Binding Header}"></Setter>
                    <Setter Property="ItemsSource" Value="{Binding Children}"></Setter>
                    <Setter Property="Command" Value="{Binding Command}"></Setter>
                </Style>
            </MenuItem.ItemContainerStyle>
        </MenuItem>
    </Menu>

你的ViewModel 可能看起来像:

public class MainWindowViewModel
{
    public MainWindowViewModel()
    {
        Items = new ObservableCollection<MenuItem>();
        ChangeCommand = new RelayCommand(ChangeCollection);
        SomethingCommand = new RelayCommand(DoSomething);
    }

    private void DoSomething()
    {
        MessageBox.Show("Hello World");
    }

    private void ChangeCollection()
    {
        this.Items.Clear();

        Items.Add(new MenuItem{Header = "Test 1"});
        Items.Add(new MenuItem{Header = "Test 2", Command = SomethingCommand});
        Items.Add(new MenuItem{Header = "Test 3"});
    }

    public RelayCommand SomethingCommand {get; set;}
    public RelayCommand ChangeCommand { get; set; }

    public ObservableCollection<MenuItem> Items { get; set; }
}

MenuItem 类:

public class MenuItem
{
    public MenuItem()
    {
        Children = new ObservableCollection<MenuItem>();
    }
    public string Header { get; set; }
    public ObservableCollection<MenuItem> Children { get; set; }
    public ICommand Command { get; set; }
}

要添加子项,只需选择您要更改子项的MenuItem,然后在该 MenuItem.Children 属性中添加或删除。

【讨论】:

  • 在我的问题中,我表示我想将MenuItems 放入MenuItems。看我贴的第二张图。我怎样才能用这种方法做到这一点?我已经尝试了&lt;Setter Property="ItemsSource"&gt;,但所有样式也适用于嵌套的MenuItems(因此我得到了无限递归)。您对此有解决方案吗?
  • 好的,我会调整的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-29
  • 1970-01-01
相关资源
最近更新 更多