2
votes

I'm trying to add an icon to a menuflyoutitem, I'd like that my menu looks similar to this one:

enter image description here

This is my code:

<AppBarButton.Flyout>
    <MenuFlyout>
        <MenuFlyoutItem Text="SMS">
            <MenuFlyoutItem.Template>
                <ControlTemplate TargetType="MenuFlyoutItem">
                    <StackPanel Margin="12,10,0,0" Orientation="Horizontal">
                        <SymbolIcon Margin="0,0,12,0" Symbol="Comment" />
                        <TextBlock Text="{TemplateBinding Text}" />
                    </StackPanel>
                </ControlTemplate>
            </MenuFlyoutItem.Template>
        </MenuFlyoutItem>
        <MenuFlyoutItem Text="Email">
            <MenuFlyoutItem.Template>
                <ControlTemplate TargetType="MenuFlyoutItem">
                    <StackPanel Margin="12,10,0,10" Orientation="Horizontal">
                        <SymbolIcon Margin="0,0,12,0" Symbol="MailForward" />
                        <TextBlock Text="{TemplateBinding Text}" />
                    </StackPanel>
                </ControlTemplate>
            </MenuFlyoutItem.Template>
        </MenuFlyoutItem>
    </MenuFlyout>
</AppBarButton.Flyout>

I've been struggling and I cannot find a normal tutorial about it, does anybody know I should change? Because when I add the icon all the behaviour of the Menu is lost for example it doesn't change the color again when I'm over the menu. Thanks.

4
You havent included visual states inside ControlTemplate of MenuFlyoutItem. So color is not changing.Archana

4 Answers

5
votes

All the behaviour of the Menu is lost because you are using your custom MenuFlyoutItem template and in your template, you didn't deal with different visual states.

By default, MenuFlyoutItem has 8 visual states which are Normal, PointerOver, Pressed, Disabled, Unchecked, Checked, DefaultPadding, and NarrowPadding. For more info, please check MenuFlyoutItem styles and templates.

When you are over the menu, it triggers PointerOver state:

<VisualState x:Name="PointerOver">
    <Storyboard>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Background">
            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListLowBrush}" />
        </ObjectAnimationUsingKeyFrames>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextBlock" Storyboard.TargetProperty="Foreground">
            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
        </ObjectAnimationUsingKeyFrames>
        <PointerUpThemeAnimation Storyboard.TargetName="TextBlock" />
    </Storyboard>
</VisualState>

And in this state, it changes the background and the TextBlock's foreground. However in your custom template, you didn't have any VisualState, so it didn't change the color.

To fix this issue, you can add visual states for each of your custom template.

Or you can create a custom style based on the default styles and templates and use Tag property to set the SymbolIcon like:

<Style x:Key="MyMenuFlyoutItem" TargetType="MenuFlyoutItem">
    <Setter Property="Background" Value="Transparent" />
    <Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}" />
    <Setter Property="Padding" Value="{ThemeResource MenuFlyoutItemThemePadding}" />
    <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
    <Setter Property="VerticalContentAlignment" Value="Center" />
    <Setter Property="UseSystemFocusVisuals" Value="True" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="MenuFlyoutItem">
                <Grid x:Name="LayoutRoot"
                      Background="{TemplateBinding Background}"
                      BorderBrush="{TemplateBinding BorderBrush}"
                      BorderThickness="{TemplateBinding BorderThickness}"
                      Padding="{TemplateBinding Padding}">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal">
                                <Storyboard>
                                    <PointerUpThemeAnimation Storyboard.TargetName="TextBlock" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="PointerOver">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Backgroun
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListLowBrush}" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextBlock" Storyboard.TargetProperty="Foreground
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}"
                                    </ObjectAnimationUsingKeyFrames>
                                    <PointerUpThemeAnimation Storyboard.TargetName="TextBlock" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Pressed">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Backgroun
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListMediumBrush}" 
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextBlock" Storyboard.TargetProperty="Foreground
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}"
                                    </ObjectAnimationUsingKeyFrames>
                                    <PointerDownThemeAnimation Storyboard.TargetName="TextBlock" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Disabled">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextBlock" Storyboard.TargetProperty="Foreground
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="CheckPlaceholderStates">
                            <VisualState x:Name="NoPlaceholder" />
                            <VisualState x:Name="CheckPlaceholder">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextBlock" Storyboard.TargetProperty="Margin">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource MenuFlyoutItemPlaceholderThemeThickness}
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="PaddingSizeStates">
                            <VisualState x:Name="DefaultPadding" />
                            <VisualState x:Name="NarrowPadding">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Padding">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource MenuFlyoutItemThemePaddingNarrow}" />
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <StackPanel Orientation="Horizontal">
                        <SymbolIcon Margin="0,0,12,0" Symbol="{Binding Tag, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
                        <TextBlock x:Name="TextBlock"
                                   HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                   VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                   Foreground="{TemplateBinding Foreground}"
                                   Text="{TemplateBinding Text}"
                                   TextTrimming="Clip" />
                    </StackPanel>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

And then, use this style in your MenuFlyoutItem:

<AppBarButton.Flyout>
    <MenuFlyout>
        <MenuFlyoutItem Style="{StaticResource MyMenuFlyoutItem}" Tag="Comment" Text="SMS" />
        <MenuFlyoutItem Style="{StaticResource MyMenuFlyoutItem}" Tag="MailForward" Text="Email" />
    </MenuFlyout>
</AppBarButton.Flyout>

The style I've used is just for example, you may need to edit it to fit your needs.

10
votes

Thanks to Windows 10 Creators Update (introduced v10.0.15063.0) MenuFlyoutItem now have a property Icon.

From Microsoft documentation :

<MenuFlyout>
    <MenuFlyoutItem Text="Share" >
        <MenuFlyoutItem.Icon>
            <FontIcon Glyph="&#xE72D;" />
        </MenuFlyoutItem.Icon>
    </MenuFlyoutItem>
</MenuFlyout>

For more information be sure to check : MenuFlyoutItem documentation

2
votes

MenuFlyoutIconGlyphIcon

 public class MenuFlyoutIconGlyph : MenuFlyoutItem
{
    public string GlyphIcon
    {
        get { return (string)GetValue(GlyphIconProperty); }
        set { SetValue(GlyphIconProperty, value); }
    }
    public static readonly DependencyProperty GlyphIconProperty =
        DependencyProperty.Register("GlyphIcon", typeof(string), typeof(MenuFlyoutIconGlyph), new PropertyMetadata("uE10C"));
}

Style

 <!--With glyph icon-->
<ControlTemplate x:Key="MenuFlyoutItemControlTemplate2" TargetType="controlEx:MenuFlyoutIconGlyph">
    <Grid x:Name="LayoutRoot" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="CommonStates">
                <VisualState x:Name="Normal">
                    <Storyboard>
                        <PointerUpThemeAnimation Storyboard.TargetName="TextBlock"/>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="PointerOver">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="LayoutRoot">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListLowBrush}"/>
                        </ObjectAnimationUsingKeyFrames>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="TextBlock">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}"/>
                        </ObjectAnimationUsingKeyFrames>
                        <PointerUpThemeAnimation Storyboard.TargetName="TextBlock"/>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="Pressed">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="LayoutRoot">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListMediumBrush}"/>
                        </ObjectAnimationUsingKeyFrames>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="TextBlock">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}"/>
                        </ObjectAnimationUsingKeyFrames>
                        <PointerDownThemeAnimation Storyboard.TargetName="TextBlock"/>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="Disabled">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="TextBlock">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
            <VisualStateGroup x:Name="CheckPlaceholderStates">
                <VisualState x:Name="NoPlaceholder"/>
                <VisualState x:Name="CheckPlaceholder">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Margin" Storyboard.TargetName="TextBlock">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource MenuFlyoutItemPlaceholderThemeThickness}"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
            <VisualStateGroup x:Name="PaddingSizeStates">
                <VisualState x:Name="DefaultPadding"/>
                <VisualState x:Name="NarrowPadding">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Padding" Storyboard.TargetName="LayoutRoot">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource MenuFlyoutItemThemePaddingNarrow}"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

        <StackPanel Margin="12,5,5,0" Orientation="Horizontal">
            <FontIcon Foreground="{TemplateBinding Foreground}"                         
                       HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                       Margin="0,0,12,0" Glyph="{TemplateBinding GlyphIcon}" 
                       VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
            <TextBlock  x:Name="TextBlock" Foreground="{TemplateBinding Foreground}"
                        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                        Text="{TemplateBinding Text}" TextTrimming="Clip" 
                        VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
        </StackPanel>
    </Grid>
</ControlTemplate>
<Style x:Key="MenuFlyoutItemStyleIconGlyph" TargetType="controlEx:MenuFlyoutIconGlyph" >
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}"/>
    <Setter Property="Padding" Value="{ThemeResource MenuFlyoutItemThemePadding}"/>
    <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
    <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="UseSystemFocusVisuals" Value="True"/>
    <Setter Property="Template" Value="{StaticResource MenuFlyoutItemControlTemplate2}">
    </Setter>
</Style>

Sample

<Grid x:Name="grid">
    <FlyoutBase.AttachedFlyout>
        <MenuFlyout MenuFlyoutPresenterStyle="{StaticResource MenuFlyoutPresenterStyle}">
            <controlEx:MenuFlyoutIconGlyph Style="{StaticResource MenuFlyoutItemStyleIconGlyph}" Text="Share" GlyphIcon="&#xE122;"></controlEx:MenuFlyoutIconGlyph>
        </MenuFlyout>
    </FlyoutBase.AttachedFlyout>

1
votes

Add the visul states for mouse hover. Here is the complete ControlTemplate of MenuFlyoutItem which is taken from this link

<MenuFlyoutItem Text="SMS">
    <MenuFlyoutItem.Template>
        <ControlTemplate TargetType="MenuFlyoutItem">
            <Grid x:Name="LayoutRoot"
                Padding="{TemplateBinding Padding}"
                Background="{TemplateBinding Background}"
                BorderBrush="{TemplateBinding BorderBrush}"
                BorderThickness="{TemplateBinding BorderThickness}">
                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup x:Name="CommonStates">
                        <VisualState x:Name="Normal">
                            <Storyboard>
                                <PointerUpThemeAnimation Storyboard.TargetName="TextBlock" />
                            </Storyboard>
                        </VisualState>
                        <VisualState x:Name="PointerOver">
                            <Storyboard>
                                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Background">
                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListLowBrush}" />
                                </ObjectAnimationUsingKeyFrames>
                                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextBlock" Storyboard.TargetProperty="Foreground">
                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
                                </ObjectAnimationUsingKeyFrames>
                                <PointerUpThemeAnimation Storyboard.TargetName="TextBlock" />
                            </Storyboard>
                        </VisualState>
                        <VisualState x:Name="Pressed">
                            <Storyboard>
                                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Background">
                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListMediumBrush}" />
                                </ObjectAnimationUsingKeyFrames>
                                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextBlock" Storyboard.TargetProperty="Foreground">
                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
                                </ObjectAnimationUsingKeyFrames>
                                <PointerDownThemeAnimation Storyboard.TargetName="TextBlock" />
                            </Storyboard>
                        </VisualState>
                        <VisualState x:Name="Disabled">
                            <Storyboard>
                                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextBlock" Storyboard.TargetProperty="Foreground">
                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
                                </ObjectAnimationUsingKeyFrames>
                            </Storyboard>
                        </VisualState>
                    </VisualStateGroup>
                    <VisualStateGroup x:Name="CheckPlaceholderStates">
                        <VisualState x:Name="NoPlaceholder" />
                        <VisualState x:Name="CheckPlaceholder">
                            <Storyboard>
                                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextBlock" Storyboard.TargetProperty="Margin">
                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource MenuFlyoutItemPlaceholderThemeThickness}" />
                                </ObjectAnimationUsingKeyFrames>
                            </Storyboard>
                        </VisualState>
                    </VisualStateGroup>
                    <VisualStateGroup x:Name="PaddingSizeStates">
                        <VisualState x:Name="DefaultPadding" />
                        <VisualState x:Name="NarrowPadding">
                            <Storyboard>
                                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Padding">
                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource MenuFlyoutItemThemePaddingNarrow}" />
                                </ObjectAnimationUsingKeyFrames>
                            </Storyboard>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>
                <StackPanel  Margin="12,10,0,10" Orientation="Horizontal">
                    <SymbolIcon Margin="0,0,12,0" Symbol="MailForward" />
                    <TextBlock
                        x:Name="TextBlock"
                        Text="{TemplateBinding Text}"
                        TextTrimming="Clip"
                        Foreground="{TemplateBinding Foreground}"
                        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                        VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                </StackPanel>
            </Grid>
        </ControlTemplate>
    </MenuFlyoutItem.Template>
</MenuFlyoutItem>