recursive menu item with default template and itemTemplate

核能气质少年 提交于 2021-02-07 12:54:43

问题


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?


回答1:


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.




回答2:


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



来源:https://stackoverflow.com/questions/33566668/recursive-menu-item-with-default-template-and-itemtemplate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!