locked
SharedSizeGroup not working between MenuItem and Separator RRS feed

  • Question

  • I have successfully styled/templated ContextMenu and MenuItem. In particular, my approach uses the sharing of sizing properties between grids (Grid.IsSharedSizeScope). Nothing really fancy; basically just setting up columns for the icon, header, input gesture text, etc. in each MenuItem and sharing them with each other.

    Style for ContextMenu

    <Style TargetType="{x:Type ContextMenu}">
    
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ContextMenu}">
    
                    <Border x:Name="PART_Border"
                            Background="White" BorderBrush="Gray" BorderThickness="1">
    
                        <StackPanel x:Name="PART_ItemsHost"
                                    IsItemsHost="True" Grid.IsSharedSizeScope="True"
                                    KeyboardNavigation.DirectionalNavigation="Cycle"/>
    
                    </Border>
    
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    
    </Style>

    Note that I have set Grid.IsSharedSizeScope="True" on the StackPanel which hosts the menu items.

    ControlTemplate for submenu items

    <ControlTemplate x:Key="{x:Static MenuItem.SubmenuItemTemplateKey}" TargetType="{x:Type MenuItem}">
    
        <Border x:Name="PART_Border" MinHeight="28" Padding="0 8 0 8" Background="Transparent">
    
            <Grid x:Name="PART_Grid" VerticalAlignment="Center">
    
                <Grid.ColumnDefinitions>
    
                    <!-- Column 0: Left padding -->
                    <ColumnDefinition Width="13"/>
    
                    <!-- Column 1: Icon -->
                    <ColumnDefinition Width="Auto" SharedSizeGroup="Icon"/>
    
                    <!-- Column 2: Header margin -->
                    <ColumnDefinition Width="10"/>
    
                    <!-- Column 3: Header -->
                    <ColumnDefinition Width="Auto" SharedSizeGroup="Header"/>
    
                    <!-- Column 4: Shortcut -->
                    <ColumnDefinition Width="Auto" SharedSizeGroup="Shortcut"/>
    
                    <!-- Column 5: Placeholder for arrow -->
                    <ColumnDefinition Width="Auto" SharedSizeGroup="Arrow"/>
    
                    <!-- Column 6: Right padding -->
                    <ColumnDefinition Width="13"/>
    
                </Grid.ColumnDefinitions>
    
                <!-- Skipping ContentPresenters for icon, header and shortcut... -->
    
            </Grid>
    
        </Border>
    
    </ControlTemplate>

    Note that I have defined a SharedSizeGroup for each column. The scope for sharing the size information is the parent StackPanel in the ContextMenu (see above).

    ControlTemplate for submenu headers

    <ControlTemplate x:Key="{x:Static MenuItem.SubmenuHeaderTemplateKey}" TargetType="{x:Type MenuItem}">
    
        <Border x:Name="PART_Border" MinHeight="28" Padding="0 8 0 8" Background="Transparent">
    
            <Grid x:Name="PART_Grid" VerticalAlignment="Center">
    
                <Grid.ColumnDefinitions>
    
                    <!-- Column 0: Left padding -->
                    <ColumnDefinition Width="13"/>
    
                    <!-- Column 1: Icon -->
                    <ColumnDefinition Width="Auto" SharedSizeGroup="Icon"/>
    
                    <!-- Column 2: Header margin -->
                    <ColumnDefinition Width="10"/>
    
                    <!-- Column 3: Header -->
                    <ColumnDefinition Width="Auto" SharedSizeGroup="Header"/>
    
                    <!-- Column 4: Shortcut -->
                    <ColumnDefinition Width="Auto" SharedSizeGroup="Shortcut"/>
    
                    <!-- Column 5: Arrow -->
                    <ColumnDefinition Width="Auto" SharedSizeGroup="Arrow"/>
    
                    <!-- Column 6: Right padding -->
                    <ColumnDefinition Width="13"/>
    
                </Grid.ColumnDefinitions>
    
                <!-- Skipping ContentPresenters for icon, header and shortcut... -->
                <!-- Skipping visual for submenu arrow... -->
    
                <Popup x:Name="PART_Popup"
                       Placement="Right" PlacementTarget="{Binding ElementName=PART_Border}"
                       HorizontalOffset="0" VerticalOffset="-1"
                       IsOpen="{TemplateBinding IsSubmenuOpen}"
                       PopupAnimation="Fade" AllowsTransparency="True"
                       Focusable="False">
    
                    <Border x:Name="PART_SubmenuBorder"
                            BorderBrush="Gray" BorderThickness="1" Background="White"
                            SnapsToDevicePixels="True">
    
                        <StackPanel x:Name="PART_SubmenuItemsHost" IsItemsHost="True"
                                    KeyboardNavigation.DirectionalNavigation="Cycle"
                                    Grid.IsSharedSizeScope="True"/>
    
                    </Border>
    
                </Popup>
    
            </Grid>
    
        </Border>
    
    </ControlTemplate>

    Note how I have defined exactly the same columns as for the submenu items, including the identical SharedSizeGroup for each column. The scope for sharing the size information is, again, the parent StackPanel in the ContextMenu. Additonally, I have set Grid.IsSharedSizeScope="True" on the StackPanel which hosts the MenuItems of the submenu. This way, every submenu has its own scope for sharing the column widths and won't interfere with the parent menu.

    All of this works fine so far.

    Next, I want to style a Separator between the menu items. With the size information sharing already set up successfully, I thought this would be effortless. My approach was this:

    <ControlTemplate x:Key="SubmenuSeparatorTemplate" TargetType="{x:Type Separator}">
    
        <Grid>
    
            <Grid.ColumnDefinitions>
    
                <!-- Column 0: Left padding -->
                <ColumnDefinition Width="13"/>
    
                <!-- Column 1: Icon -->
                <ColumnDefinition Width="Auto" SharedSizeGroup="Icon"/>
    
                <!-- Column 2: Header margin -->
                <ColumnDefinition Width="10"/>
    
                <!-- Column 3: Header -->
                <ColumnDefinition Width="Auto" SharedSizeGroup="Header"/>
    
                <!-- Column 4: Shortcut -->
                <ColumnDefinition Width="Auto" SharedSizeGroup="Shortcut" />
    
                <!-- Column 5: Arrow -->
                <ColumnDefinition Width="Auto" SharedSizeGroup="Arrow" />
    
                <!-- Column 6: Right padding -->
                <ColumnDefinition Width="13"/>
    
            </Grid.ColumnDefinitions>         
    
            <Rectangle Grid.Column="3" Grid.ColumnSpan="4" Height="1" Fill="Gray"/>
    
        </Grid>
    
    </ControlTemplate>
    
    <!-- Style for separators between menu items -->
    <Style x:Key="{x:Static MenuItem.SeparatorStyleKey}" TargetType="{x:Type Separator}">
        <Setter Property="Template" Value="{StaticResource SubmenuSeparatorTemplate}"/>
    </Style>

    Basically, I want to draw a line starting from the header column all the way to the right edge of the menu item. Note how I defined the same column structure and SharedSizeGroups as for the actual menu items.

    However, this isn't really working. While the size sharing between the MenuItems still behaves as desired, sharing the size information with the Separator appears to be broken. I expected to be able to share the size information between both types since they are within a common sharing scope, namely the StackPanel in the ContextMenu template. But all I get is a misaligned and way too short line.

    Am I missing something here? Any help would be appreciated!

    Thank you very much in advance! 

    Friday, March 13, 2020 8:28 PM

All replies