locked
Control.Template MenuItem RRS feed

  • Question

  • I have been learning a lot about general workflows for styles and templates. I am using Resource Dictionaries to store my styles and my applications brushes and colors. I am currently working on styles and control templates for certain elements of my UI and I am struggling with making a control template for the MenuItem.

    Currently I have made a short style for a Menu and I am looking to put MenuItem's within it (just like the standard Menu and MenuItems) but I can't seem to get any MenuItem's to show when using my style.

    Here is my code snippet of my XAML for my Menu:

    <!--Top Level Menu-->
        <Style x:Key="S2ENGINE.TopLevelMenu" TargetType="{x:Type Menu}">
            <Setter Property="Height" Value="32"/>
    
            <!--Setting Menu Template-->
            <Setter Property="Template">
                <Setter.Value>
                    
                    <!--Menu Template-->
                    <ControlTemplate TargetType="{x:Type Menu}">
                        <Menu Background="{StaticResource S2ENGINEGradientBrush}"
                              BorderBrush="{StaticResource S2ENGINEBorderBrushTransparent}"
                              BorderThickness="0"/>
    
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

    Here is a code snippet of my XAML for my MenuItem: 

    <!--Top Level MenuItems-->
        <Style x:Key="S2ENGINE.TopLevelMenuItem" TargetType="{x:Type MenuItem}">
    
            <!--Setting MenuItems Template-->
            <Setter Property="Template">
                <Setter.Value>
    
                    <!--Menu Template-->
                    <ControlTemplate TargetType="{x:Type MenuItem}">
                        <MenuItem Foreground="{StaticResource S2ENGINETextBrush}"
                                  FontFamily="Segeo UI Light"
                                  FontSize="14"
                                  Header="{TemplateBinding Header}"
                                  Icon="{TemplateBinding Icon}"
                                  IsCheckable="{TemplateBinding IsCheckable}"
                                  ToolTip="{TemplateBinding ToolTip}"
                                  BorderThickness="0">
    
                            <!--Content Placement-->
                            <ContentPresenter x:Name="MenuItemContentPresenter"
                                                  VerticalAlignment="Center"
                                                  HorizontalAlignment="Center"/>
                            
                        </MenuItem>
    
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

    I have a separate Resource Dictionary called "Brushes.xaml" which is just storing SolidColorBrush and LinearGradientBrush to use in my styles (just in case you were wondering what the StaticResource's were).

    Here is the usage in my MainWindow.xaml:

    <Grid>
    
            <StackPanel>
                <Menu Style="{StaticResource S2ENGINE.TopLevelMenu}">
                    <MenuItem Header="File" Style="{StaticResource S2ENGINE.TopLevelMenuItem}"/>
                    <MenuItem Header="Edit" Style="{StaticResource S2ENGINE.TopLevelMenuItem}"/>
                </Menu>
            </StackPanel>
        </Grid>

    And here is a screenshot showing the result in Designer View:

    I have two Headers there and nothing is showing up at all. Not to sure where I am going wrong. Any help is appreciated! 

    Thanks,

    Dave.



    Thursday, November 10, 2016 1:41 AM

Answers

  • When you show a collection of stuff these are Items in WPF speak.

    If you look at listbox. datagrid and menu, these all inherit from itemscontrol.

    A control which shows a collection of Items.

    They all do so inside an ItemsPresenter.

    This is probably clearer if you take a look at the visual tree of a running app which has a few things in an itemscontrol and then again a few in a menu ( without your template ).

    Anyhow, if you have no itemspresenter in your template then you have nothing which will hold the items, same with a menuitem. It can have no children if you don't give it an itemspresenter.

    That template applies to the menu which exposes all the properties you have set there.

    It's therefore a bad idea to use a template to make those changes.

    You can do the same with a style.

    This is preferable because it's less intrusive - eg you can't inadvertently leave out the itemspresenter.

    Anyhow:

            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid.Resources>
                <Style TargetType="Menu">
                    <Setter Property="Background" Value="Yellow"/>
                    <Setter Property="BorderBrush" Value="Red"/>
                    <Setter Property="BorderThickness" Value="2"/>
                </Style>
            </Grid.Resources>
            <Menu> 
                <MenuItem Header="_File" >
                    <MenuItem Header="_Open" Name="OpenMenu"/>
                    <MenuItem Header="_Save" />
                    <Separator />
                    <MenuItem Header="_Exit" />
                </MenuItem>
            </Menu>

    I'm using fixed colours (for simplicity) there, you could use a resource brush instead.

    If you set borderthickness to zero then setting the borderbrush is a bit pointless BTW.

    .

    If you're learning wpf then I have a load of samples and articles on the TechNet wiki and gallery you might find useful.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    Thursday, November 10, 2016 2:37 PM

All replies

  • A ControlTemplate for a Menu should not include another Menu element. It should include an ItemsPresenter:

    <Style x:Key="S2ENGINE.TopLevelMenu" TargetType="{x:Type Menu}">
                <Setter Property="Height" Value="32"/>
                <!--Setting Menu Template-->
                <Setter Property="Template">
                    <Setter.Value>
                        <!--Menu Template-->
                        <ControlTemplate TargetType="{x:Type Menu}">
                            <Border Background="{StaticResource S2ENGINEGradientBrush}"
                              BorderBrush="{StaticResource S2ENGINEBorderBrushTransparent}"
                              BorderThickness="0">
                                <ItemsPresenter />
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>

    An ItemsPresenter is used within the template of an item control to specify the place in the control’s visual tree where the items are to be added: https://msdn.microsoft.com/en-us/library/system.windows.controls.itemspresenter%28v=vs.110%29.aspx

    Hope that helps.

    Please remember to close your threads by marking helpful posts as answer and then start a new thread if you have a new question. Please don't ask several questions in the same thread.

    Thursday, November 10, 2016 3:27 AM
  • Just to clarify, when working on a control template for a menu within the control template:

    <ControlTemplate TargetType="{x:Type Menu}">
                            <Border Background="{StaticResource S2ENGINEGradientBrush}"
                              BorderBrush="{StaticResource S2ENGINEBorderBrushTransparent}"
                              BorderThickness="0">
                                <ItemsPresenter />
                            </Border>
     

    There cannot be any other elements for the menu inside the control template? So in my above example where I have my <Border> tags that should be replaced with an item presenter and inside the item presenter I then specify my brushes/properties for my menu?

    Sorry if I am just repeating what you suggested I am still pretty new at WPF and XAML.

    Thursday, November 10, 2016 11:16 AM
  • When you show a collection of stuff these are Items in WPF speak.

    If you look at listbox. datagrid and menu, these all inherit from itemscontrol.

    A control which shows a collection of Items.

    They all do so inside an ItemsPresenter.

    This is probably clearer if you take a look at the visual tree of a running app which has a few things in an itemscontrol and then again a few in a menu ( without your template ).

    Anyhow, if you have no itemspresenter in your template then you have nothing which will hold the items, same with a menuitem. It can have no children if you don't give it an itemspresenter.

    That template applies to the menu which exposes all the properties you have set there.

    It's therefore a bad idea to use a template to make those changes.

    You can do the same with a style.

    This is preferable because it's less intrusive - eg you can't inadvertently leave out the itemspresenter.

    Anyhow:

            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid.Resources>
                <Style TargetType="Menu">
                    <Setter Property="Background" Value="Yellow"/>
                    <Setter Property="BorderBrush" Value="Red"/>
                    <Setter Property="BorderThickness" Value="2"/>
                </Style>
            </Grid.Resources>
            <Menu> 
                <MenuItem Header="_File" >
                    <MenuItem Header="_Open" Name="OpenMenu"/>
                    <MenuItem Header="_Save" />
                    <Separator />
                    <MenuItem Header="_Exit" />
                </MenuItem>
            </Menu>

    I'm using fixed colours (for simplicity) there, you could use a resource brush instead.

    If you set borderthickness to zero then setting the borderbrush is a bit pointless BTW.

    .

    If you're learning wpf then I have a load of samples and articles on the TechNet wiki and gallery you might find useful.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    Thursday, November 10, 2016 2:37 PM
  • Awesome and thanks so much for the explanation! 

    I'll check out your articles and samples, really appreciate it. The community here is just amazing, great support from very knowledgeable people!

    In regards to making a custom Menu with MenuItems was that I wanted to be able to control the style triggers for the different conditions such as, MouseHover, MouseLeave, etc and also be able to add my own brushes to style the Menu and MenuItems.

    Also thanks for clearing up the border thing too, I thought it was abit overkill. Everytime I use a Menu and MenuItem's there is always this annoying border when you hover the mouse over items.




    Thursday, November 10, 2016 3:09 PM