WPF Menu - How to use a different template for top-level items

1.2k Views Asked by At

I would like to apply different templates to my WPF menu control depending on whether the item is a "top level" item or not. In particular, I want a larger icon above the text for top-level items and a smaller icon to the left of the text for the other items.

This is the (working) XAML I'm using now, which correctly formats the top-level items but leaves the other items looking silly and too-large:

<WrapPanel Height="Auto">
    <Menu ItemsSource="{Binding DataContext.EventMenu.TopLevel, ElementName=UserControl}">
        <Menu.ItemContainerStyle>
            <Style TargetType="{x:Type MenuItem}">
                <Setter Property="IsEnabled" Value="true"/>
                <Setter Property="Command" Value="{Binding Command}" />
                <Setter Property="CommandParameter" Value="{Binding EventType}"/>
            </Style>
        </Menu.ItemContainerStyle>
        <Menu.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                    <Image Grid.Row="0" Width="32" Height="32"  Margin="5" VerticalAlignment="Center" Source="{Binding Icon32}"/>
                    <TextBlock Grid.Row="1" Margin="5" Text="{Binding Name}"/>
                </Grid>
            </HierarchicalDataTemplate>
        </Menu.ItemTemplate>
    </Menu>
</WrapPanel>

I'd like the other items to have a template like this:

                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Height="*"/>
                        <ColumnDefinition Height="Auto"/>
                    </Grid.ColumnDefinitions>
                    <Image Grid.Column="0" Width="16" Height="16"  Margin="5" VerticalAlignment="Center" Source="{Binding Icon16}"/>
                    <TextBlock Grid.Column="1" Margin="5" Text="{Binding Name}"/>
                </Grid>

How can I have two different templates distinguished by "top-levelness". I would prefer not to have to add a property to indicate which is a top-level item, but can do so if necessary.

1

There are 1 best solutions below

3
On

You should create two styles for the menu control (in a separate resource dictionary). One is with a style key (for the top-level items) and another one without a key so that one will be the default style. Therefore you need to set the style explicitly only in the top-level items.