0

我是 WPF 和 MVVM 的新手。我已经寻找了一种在 MVVM 部分中动态创建菜单的好方法,但我没有找到任何我喜欢的东西,所以我推出了自己的解决方案。它可以工作,但由于某种原因,菜单的前景(文本)颜色有时(只是有时)不正确。

我为下面的图片添加了一个链接。

http://img220.imageshack.us/img220/1912/badmenu.jpg(死链接)

我的最低子菜单以白色前景正确显示,但其父菜单前景变为黑色,几乎无法阅读。如果我对菜单进行了硬编码,那么父级的前景色将为白色。如果我将鼠标移到父级上,它的文本将切换回白色,子菜单将变为黑色。

此外,一旦我将鼠标从父级移开,它的所有布尔属性都IsHighlighted, IsSubmenuOpen, etc...变为错误,这让我感到惊讶,因为我认为它们应该保持真实。最终结果是我无法用样式触发器解决这个问题。

这是我的 XAML 。

<Window.Resources>
  <DataTemplate DataType="{x:Type src:ParentMenu}" >
    <Menu >
      <MenuItem Header="{Binding MenuName}" ItemsSource="{Binding ChildMenuItems}" />
    </Menu>
  </DataTemplate>

  <HierarchicalDataTemplate DataType="{x:Type src:ChildMenu}" 
                          ItemsSource="{Binding ChildMenuItems}" >
    <MenuItem Header="{Binding MenuName}" Command="{Binding Path=Command}" />
  </HierarchicalDataTemplate>

' StackOverflow 为 Window.Resources 屏蔽了我的结束标记

<DockPanel>
   <Menu DockPanel.Dock="Top" ItemsSource="{Binding Menus}" />

  <Grid>
       <!-- Add additional content here -->
  </Grid>
</DockPanel>

两者都ParentMenu继承自一个公共类,该类实际上包含所有菜单并通过集合ChildMenu公开子菜单。是一个对象列表。我公开了一个对象列表。ChildMenuItemsChildMenuItemsChildMenuViewModelsParentMenu

可能有更好的方法可以在这里完成我想要的。这是一个例子:

img132.imageshack.us/img132/4160/bettermenu.jpg(死链接)

关于我做错了什么和/或如何解决显示问题的任何建议?

4

2 回答 2

1

问题是您的 VM 会自动包装在 MenuItems 中,因此您基本上将 MenuItems 嵌套为 MenuItems 的 Header。

您可以通过使用 MenuItem 作为 DataType 定义一个样式(并通过 ItemContainerStyle 指向它)来解决此问题,该样式将 DataBinds 到您的 VM(名称到 Header、DelegateCommands 到 Command 等)。

下面是您可以执行此操作的一个示例。请注意,我已经放弃了 HierarchicalDataTemplate 以支持 ItemContainerStyle。我还冒昧地为您的 MainViewModel 定义了一个 DataTemplate,因为它不是很清楚它是如何绑定数据的。

<Window.Resources>
    <DataTemplate DataType="{x:Type src:MainViewModel}">
        <ItemsControl ItemsSource="{Binding Menus}"></ItemsControl>
    </DataTemplate>
    <DataTemplate DataType="{x:Type src:ParentMenu}" >
        <Menu>
            <MenuItem Header="{Binding Name}" 
        ItemsSource="{Binding ChildMenuItems}" ItemContainerStyle="{DynamicResource ChildMenuItemStyle}" />
        </Menu>
    </DataTemplate>
    <Style x:Key="ChildMenuItemStyle" TargetType="MenuItem">
        <Setter Property="Header" Value="{Binding Name}"></Setter>
        <Setter Property="ItemsSource" Value="{Binding ChildMenuItems}"></Setter>
    </Style>
</Window.Resources>

为简单起见,我还删除了一些 Command 绑定,但您可以根据需要将其重新添加。

于 2009-06-18T18:32:16.657 回答
0

根据要求,这是我的 ViewModel。

ViewModelBase 是工作室创建的标准模型。MainVieModel 有足够的内容来创建我用来试验的测试菜单。

基本上,我正在努力创建一个父/子菜单类,我可以将其与我们出售给广大客户的一系列应用程序一起使用。我希望让每个客户都可以根据他们的需求以及他们为哪些模块购买许可证而拥有可定制的菜单集合。

public abstract class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}   

公共类 MainViewModel : ViewModelBase

{

    public MainViewModel()  {   MakeMenus();    }

    private void MakeMenus()
    {
        // Makes some dummy menus to test with.
        Menus = new ObservableCollection<MyMenuItem>();
        ParentMenu parent;
        ChildMenu child;

        parent = new ParentMenu("First Level");
        Menus.Add(parent);
        child = new ChildMenu(parent, "second level");
        parent.ChildMenuItems.Add(child);
        ChildMenu child2 = new ChildMenu(child, "third level");
        child2.MenuCommand = new DelegateCommand(CommandTest,
                                                   CommandCanExecute_First);
        child.ChildMenuItems.Add(child2);

        child = new ChildMenu(parent, "second level 2");
        parent.ChildMenuItems.Add(child);
        child2 = new ChildMenu(child, "third level 2");
        child2.MenuCommand = new DelegateCommand(CommandTest, 
                                       CommandCanExecute_Second);
        child.ChildMenuItems.Add(child2);

        parent = new ParentMenu("Another First");
        parent.ChildMenuItems.Add(new ChildMenu(parent, "Another Second"));
        Menus.Add(parent);
        OnPropertyChanged("Menus");
    }

    private bool ExecuteToggle { get; set; }
    private void CommandTest()  {   ExecuteToggle = !ExecuteToggle; } 
    public ObservableCollection<MyMenuItem> Menus  {  get; private set;}
    public bool CommandCanExecute_First()   {   return ExecuteToggle;   }
    public bool CommandCanExecute_Second() { return !ExecuteToggle;     }
}
于 2009-06-18T14:21:26.467 回答