recursive menu item with default template and itemTemplate
Asked Answered
F

2

8

I have a WPF Control template for the MenuItem type:

<Style TargetType="{x:Type MenuItem}">
    <Setter Property="Background"
            Value="Transparent" />
    <Setter Property="Cursor"
            Value="Hand" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type MenuItem}">
                <Border Background="{TemplateBinding Background}">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>
                        <ContentControl Content="{TemplateBinding Header}"
                                        Margin="5"
                                        Grid.Column="1" />
                        <Path Grid.Column="2"
                                x:Name="Indicator"
                                Data="M1,1 L1,9 9,5Z"
                                Fill="{StaticResource GlyphBrush}"
                                Margin="4"
                                Visibility="Hidden"
                                VerticalAlignment="Center" />
                        <Popup Name="PART_Popup"
                                Placement="Right"
                                IsOpen="{TemplateBinding IsSubmenuOpen}"
                                AllowsTransparency="True"
                                Grid.Column="0"
                                Grid.ColumnSpan="2"
                                HorizontalOffset="3"
                                VerticalOffset="-1">
                            <Border Background="Transparent">
                                <ContentControl Style="{StaticResource PopupContentStyle}">
                                    <ItemsPresenter/>
                                </ContentControl>
                            </Border>
                        </Popup>
                    </Grid>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsChecked"
                                Value="true">
                        <Setter Property="Background"
                                Value="{StaticResource ButtonHoverBackgroundBrush}" />
                    </Trigger>
                    <Trigger Property="IsChecked"
                                Value="false">
                        <Setter Property="Background"
                                Value="{StaticResource BackgroundBrush}" />
                    </Trigger>
                    <Trigger Property="HasItems"
                                Value="True">
                        <Setter TargetName="Indicator"
                                Property="Visibility"
                                Value="Visible" />
                    </Trigger>
                    <Trigger Property="IsEnabled"
                                Value="False">
                        <Setter Property="Opacity"
                                Value="{StaticResource DisabledTransparency}" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <Trigger Property="IsMouseOver"
                    Value="True">
            <Setter Property="Background"
                    Value="{StaticResource ButtonHoverBackgroundBrush}" />
        </Trigger>
    </Style.Triggers>
</Style>

If I do now add items to a MenuItem the template works flawless. But if I try to add items to a bound ObservableCollection I run into problems as my ControlTemplate does not use the ItemTemplate of the original MenuItem anywhere.

This usage causes problems:

<MenuItem Header="{userInterface:Translation Language}"
          ItemsSource="{Binding AvailableLanguages}">
    <MenuItem.ItemTemplate>
        <DataTemplate>
            <MenuItem Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.ChangeLanguageCommand}"
                      CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Header}"
                      Header="{Binding}" />
            </DataTemplate>
    </MenuItem.ItemTemplate>
</MenuItem>

The MenuItem does not use the Template I specified above, instead it does again take my default template.

I tried changing the ItemsPresenter of my global template to a ItemsControl but it did change nothing.

How can I solve the problem?

Flak answered 6/11, 2015 at 12:19 Comment(0)
F
3

I got this fixed by changing the ItemTemplate to a ItemContainerStyle: this is the result:

    <MenuItem Header="{userInterface:Translation Language}"
                ItemsSource="{Binding AvailableLanguages}">
        <MenuItem.ItemContainerStyle>
            <Style TargetType="MenuItem"
                    BasedOn="{StaticResource {x:Type MenuItem}}">
                <Setter Property="Header"
                        Value="{Binding Name}" />
                <Setter Property="Command"
                        Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.ChangeLanguageCommand}" />
                <Setter Property="CommandParameter"
                        Value="{Binding RelativeSource={RelativeSource Self}, Path=DataContext}" />
                <Setter Property="IsChecked"
                        Value="{Binding IsSelected}">
                </Setter>
            </Style>
        </MenuItem.ItemContainerStyle>
    </MenuItem>

Problem of the initial ItemTemplate is that the MenuItem internal uses a MenuItem as item container template. which resulted in a MenuItem inside a MenuItem where the Command and the CommandProperty where on the inner MenuItem while the Style was on the outer MenuItem. Which was causing Problems with my Command because the outer MenuItem already consumes the Click.

Now using the ItemContainerStyle the setters get applied to the correct MenuItem while using the BasedOn property takes all Setters of the Global MenuItem style.

Flak answered 12/11, 2015 at 17:37 Comment(0)
M
1

Console,

  1. Name your style :
<Style x:Key="MenuItemStyle1" TargetType="{x:Type MenuItem}">
  1. And every time you intend to use it, use the named resource :
 <MenuItem Header="Hello" 
           ItemsSource="{Binding AvailableLanguages}"
           Style="{DynamicResource MenuItemStyle1}">
   <MenuItem.ItemTemplate>
     <DataTemplate>
       <MenuItem Style="{DynamicResource MenuItemStyle1}" 
                 Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.ChangeLanguageCommand}"
                 CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Header}">
         <MenuItem.Header>
           <TextBlock Text="Hello" />
         </MenuItem.Header>
       </MenuItem>
     </DataTemplate>
   </MenuItem.ItemTemplate>

Regards

Moonstruck answered 9/11, 2015 at 20:35 Comment(2)
I tried this out but it shows no Effekt, the gloabal MenuItem Template is still not consuming the item template anywhere.Flak
Of course like in the above post, you assign the style to BOTH menus, do you ? I just posted my project. I got it working(even if it is really ugly). 1drv.ms/1GWDPUmMoonstruck

© 2022 - 2024 — McMap. All rights reserved.