WPF - How to style the menu control to remove the left margin?

后端 未结 9 1507
余生分开走
余生分开走 2021-02-04 08:41

I have added a default menu control to my user control. I need to style the menu to remove the left margin containing the space for the icon or checkbox. How can I do this?

相关标签:
9条回答
  • 2021-02-04 09:07

    To remove the space and never use icons you have to change the template of MenuItem.SubmenuItemTemplateKey or the template of MenuItem. If you just need to get read of the vertical line and keep using the icons space folow this answare.

    Windows with grid has my CustomContextMenu.xaml as grid resource:

    <Window ...>
        <Grid>
            <Grid.Resources>
                <ResourceDictionary Source="CustomContextMenu.xaml"/>
            </Grid.Resources>
            <Grid.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Menu item 1" >
                        <MenuItem Header="Menu item 2" >
                            <MenuItem.Icon>
                                <Image Source="icon.jpg"/>
                            </MenuItem.Icon>
                        </MenuItem>
                    </MenuItem>
                    <Separator Style="{StaticResource MySeparatorStyle}" />
                    <MenuItem IsEnabled="False" Header="Menu item 3" />
                </ContextMenu>
            </Grid.ContextMenu>
            <TextBlock>test</TextBlock>
        </Grid>
    </Window>
    

    Here is my CustomContextMenu.xaml that has a CustomSeparatorStyle template to extend the separation line to the left margin of the context menu. And a ContextMenu template to hide the vertical line.

    <ResourceDictionary
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
            <!-- Outer menu -->
    <Style TargetType="{x:Type ContextMenu}">
        <Setter Property="OverridesDefaultStyle" Value="True" />
        <Setter Property="MaxWidth" Value="295" />
        <Setter Property="SnapsToDevicePixels" Value="True" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ContextMenu}">
                    <!--Here is where you change the border thickness to zero on the menu-->
                    <Border BorderThickness="1"
                            x:Name="Border"
                            CornerRadius="0"
                            BorderBrush="{TemplateBinding BorderBrush}"
                    Background="#CCCCC7">
                        <Border.Effect>
                            <DropShadowEffect
                            ShadowDepth="2" Color="Black" Direction="135" Opacity=".8"/>
                        </Border.Effect>
                        <StackPanel ClipToBounds="True"
                                    Orientation="Vertical"
                                    IsItemsHost="True" />
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter TargetName="Border"
                                    Property="Background"
                                    Value="#F7F7F4" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
        <!-- Separator -->
        <Style TargetType="{x:Type Separator}" x:Key="CustomSeparatorStyle">
            <Setter Property="Height" Value="1" />
            <Setter Property="Margin" Value="-30,5,0,5"/>
            <Setter Property="Background" Value="#F7F7F4" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Separator}">
                        <Border BorderBrush="#DADAD6" BorderThickness="1" />
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    

    The right sude menu is created with the code above. You can notice the difference in size and shadow. In order to keep the shadow of the original menu you have to exclude the Border.Effect

    0 讨论(0)
  • 2021-02-04 09:08

    Thanks for succesfull idea. For .net Framework 4.5 and VS 2012 I wrote for ContextMenu and MenuItem accordingly:

            private const double ICON_SIZE = 32;
    
        void ContextMenu_Loaded(object sender, System.Windows.RoutedEventArgs e)
        {
            if (_pointerControl.ContextMenu.Template != null)
            {
                System.Windows.Shapes.Rectangle r1 = _pointerControl.ContextMenu.Template.FindName("3_T", _pointerControl.ContextMenu) as System.Windows.Shapes.Rectangle;
                System.Windows.Shapes.Rectangle r2 = _pointerControl.ContextMenu.Template.FindName("4_T", _pointerControl.ContextMenu) as System.Windows.Shapes.Rectangle;
                System.Windows.Shapes.Rectangle r3 = _pointerControl.ContextMenu.Template.FindName("5_T", _pointerControl.ContextMenu) as System.Windows.Shapes.Rectangle;
                double width = Math.Max(28, ICON_SIZE+14);
                r1.Width = width;
                r2.Margin = new System.Windows.Thickness(width + 1, 2, 0, 2);
                r3.Margin = new System.Windows.Thickness(width + 2, 2, 0, 2);
    
            }
        }
    
        void mi_Loaded(object sender, System.Windows.RoutedEventArgs e)
        {
            System.Windows.Controls.MenuItem mi = sender as System.Windows.Controls.MenuItem;
            if (mi != null && mi.Template != null)
            {
                System.Windows.Controls.ContentPresenter cp = mi.Template.FindName("Icon", mi) as System.Windows.Controls.ContentPresenter;
                cp.Height = ICON_SIZE + 6;
                cp.Width = ICON_SIZE + 6;
            }
    
        }
    
    0 讨论(0)
  • 2021-02-04 09:09

    Use a RadMenuGroupItem.

    RadMenuGroupItem inherits from RadMenuItem class and it is used as container of a RadMenuItem dropdown. In other words any UI element can be placed inside of RadMenuGroupItem. By default the background color of RadMenuGroupItem is White and there is no Icon area with different color unlike RadMenuItem, so you can easily use different sized Icons in the dropdown. In addition to this RadMenuGroupItem also has a Header property which is displayed on the top of all the group items.

    <telerik:RadMenu VerticalAlignment="Top">
    <telerik:RadMenuItem Header="Shapes" />
    <telerik:RadMenuItem Header="Sizes">
        <telerik:RadMenuGroupItem Header="Header">
            <telerik:RadMenuItem Header="Small" IconTemplate="{StaticResource IconTemplate}" IconColumnWidth="35" Height="35" />
            <telerik:RadMenuItem Header="Medium" IconTemplate="{StaticResource IconTemplate}" IconColumnWidth="45" Height="45" />
            <telerik:RadMenuItem Header="Large" IconTemplate="{StaticResource IconTemplate}" IconColumnWidth="55" Height="55" />
        </telerik:RadMenuGroupItem>
    </telerik:RadMenuItem>
    

    And this is the result:

    0 讨论(0)
  • 2021-02-04 09:11

    Simpal and Sort way is below: Create an ItemsPanelTemplate resource

    <ItemsPanelTemplate x:Key="MenuItemPanelTemplate">
        <StackPanel  Background="White"/>
    </ItemsPanelTemplate>
    

    Add below MenuItem style to resources and you are done.

    <Style TargetType="{x:Type MenuItem}">
       <Setter Property="ItemsPanel" Value="{StaticResource MenuItemPanelTemplate}"/>
    </Style>
    

    To apply same Style to a ContextMenu, you need to create one more Style as following-

    <Style TargetType="{x:Type ContextMenu}">
       <Setter Property="ItemsPanel" Value="{StaticResource MenuItemPanelTemplate}"/>
    </Style>
    

    also above of that for context menu you have to add

    <ContextMenu ItemsSource="{Binding MyItems}" >
        <ContextMenu.ItemTemplate>
            <DataTemplate>
                    <TextBlock Margin="-20,0,-40,0" Text="{Binding Name}"/>
            </DataTemplate>
        </ContextMenu.ItemTemplate>
    </ContextMenu>
    

    so it will override icon space and show case textblock.It is the simple and most easy solution.

    0 讨论(0)
  • 2021-02-04 09:16

    Two options here:

    1. Short, simple and straight forward. Set ItemsPanelTemplate for MenuItem or ContextMenu, depending what kind of menu you are using (see details).

    2. Radical. Rewrite Menu style from scratch. There are two ready to use styles:

      • XAML-style of Menu from MahApps.Metro (ordinary Menu and ContextMenu)
      • Jeff Wilcox's style which inspired the previous one from MahApps (link)
    0 讨论(0)
  • 2021-02-04 09:23

    It's not very straight forward, but you need to create a MenuItemStyle, easiest through Expression Blend:

    <Menu>
        <MenuItem Header="MyMenu" Style="{DynamicResource MenuItemStyle1}">
            <MenuItem Header="Options..." />
            <MenuItem Header="About" />
        </MenuItem>
    </Menu> 
    

    It creates an extremely verbose set of templates and styles, and you need to edit the menu item to remove the fixed width first column of the grid, then in the SubMenuBorder ContentControl template, remove the rectangles which form the background shading. I've attached a sample project with margins removed. Download sample project here.

    0 讨论(0)
提交回复
热议问题