Search code examples
wpfmvvmmenuforeground

WPF, MVVM, and Menu Foreground Color


I'm new to both WPF and MVVM. I have searched for a good way to dynamically create menus in the MVVM parttern and I am not finding anything to my liking, so I rolled my own solution. It works, but for some reason the Foreground (text) color of the menus are sometimes (just sometimes) not correct.

I added a link for the image below.

http://img220.imageshack.us/img220/1912/badmenu.jpg (Dead Link)

My lowest submenu displays correctly with a white foreground, but its parent menus forground turned to black and is almost impossible to read. If I had hard coded the menus then the parent's forground color would be white. If I move my mouse over the parent its text will switch back to white and the submenu will become black.

Further, once I move my mouse away from the parent, all of its boolean properties IsHighlighted, IsSubmenuOpen, etc... become false, which surprising to me because I would think they should stay true. The end result is I haven't been able to solve this with a style trigger.

Here is my 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 is masking my end tag for Window.Resources

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

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

Both ParentMenu and ChildMenu inherit from a common class that actually holds all the menus and exposes the sub-menus through the ChildMenuItems collection. ChildMenuItems is a list of ChildMenu objects. My ViewModels expose a list of ParentMenu objects.

There are probably better ways to accomplish what I want here. Here is an example:

img132.imageshack.us/img132/4160/bettermenu.jpg (Dead Link)

Any suggestions on what I'm doing wrong and/or how to fix the display problem?


Solution

  • The problem is that your VMs automatically get wrapped in MenuItems, so you essentially have MenuItems nested as the Header of MenuItems.

    You can get around this by defining a Style (and pointing to it via ItemContainerStyle) that DataBinds to your VMs (Name to Header, DelegateCommands to Command, etc.) using MenuItem as the DataType.

    An example of a way you can do this is below. Note that I've dropped the HierarchicalDataTemplate in favor of an ItemContainerStyle. I also took the liberty of defining a DataTemplate for your MainViewModel as it wasn't very clear how that was data bound.

    <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>
    

    I've also cut some of the Command binding out for simplicity, but you can add it back in as necessary.