问题
I am trying to build a CommandBar that looks like this:
Desired CommandBar with SecondaryCommands that have icons
But I can't find a way to edit the default style of CommandOverflowPresenter in order to show SecondaryCommands like they are shown in Mail Windows 10 universal app, with icons on the left and text labels on the right.
The CommandOverflowPresenter doesn't have a Content property to build a control template around it and bind content elements to AppBarButton Icon and Label properties.
I found this article, but it doesn't show the Style for the AppBarButton.
There was another question on Stack Overflow, and the conclusion is to build a custom CommandOverflowPresenter style. How do you do that?
Default CommandOverflowPresenter style:
<!-- Default style for Windows.UI.Xaml.Controls.CommandBarOverflowPresenter -->
<Style TargetType="CommandBarOverflowPresenter">
<Setter Property="Background" Value="{ThemeResource SystemControlBackgroundChromeMediumLowBrush}" />
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundChromeHighBrush}" />
<Setter Property="MaxWidth" Value="{ThemeResource CommandBarOverflowMaxWidth}"/>
<Setter Property="ScrollViewer.HorizontalScrollMode" Value="Disabled" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
<Setter Property="ScrollViewer.VerticalScrollMode" Value="Auto" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.ZoomMode" Value="Disabled" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CommandBarOverflowPresenter">
<Grid x:Name="LayoutRoot" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}"
BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1,1,1,1" >
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="DisplayModeStates">
<VisualState x:Name="DisplayModeDefault" />
<VisualState x:Name="FullWidthOpenDown" >
<VisualState.Setters>
<Setter Target="LayoutRoot.BorderThickness" Value="0,0,0,1" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="FullWidthOpenUp" >
<VisualState.Setters>
<Setter Target="LayoutRoot.BorderThickness" Value="0,1,0,0" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ScrollViewer
HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}"
AutomationProperties.AccessibilityView="Raw">
<ItemsPresenter x:Name="ItemsPresenter" Margin="0,7,0,7"/>
</ScrollViewer>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This is what I tried.
CommandOverflowPresenter is an ItemsControl and I added a Setter for its ItemTemplate in CommandOverflowPresenter style, and let the Content template as it was in the default style.
When running, the secondary commands are displayed according to the default style, only text labels are displayed, but not the icons.
Perhaps the bindings are not set up properly in the ItemTemplate's DataTemplate?
<CommandBar.CommandBarOverflowPresenterStyle>
<Style TargetType="CommandBarOverflowPresenter">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CommandBarOverflowPresenter">
<Grid x:Name="LayoutRoot" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}"
BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1,1,1,1" >
<!--<Grid.Resources>
<DataTemplate x:Key="SecondaryMenu">
<StackPanel Orientation="Horizontal">
<SymbolIcon Symbol="{TemplateBinding AppBarButton.Icon}"/>
<TextBlock Text="{TemplateBinding AppBarButton.Label}" />
</StackPanel>
</DataTemplate>
</Grid.Resources>-->
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="DisplayModeStates">
<VisualState x:Name="DisplayModeDefault" />
<VisualState x:Name="FullWidthOpenDown" >
<VisualState.Setters>
<Setter Target="LayoutRoot.BorderThickness" Value="0,0,0,1" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="FullWidthOpenUp" >
<VisualState.Setters>
<Setter Target="LayoutRoot.BorderThickness" Value="0,1,0,0" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ScrollViewer
HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}"
AutomationProperties.AccessibilityView="Raw">
<ItemsPresenter x:Name="ItemsPresenter" Margin="0,7,0,7">
</ItemsPresenter>
</ScrollViewer>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate x:DataType="AppBarButton">
<StackPanel Orientation="Horizontal">
<SymbolIcon Symbol="{Binding Icon}" />
<TextBlock Text="{Binding Label}" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</CommandBar.CommandBarOverflowPresenterStyle>
I also tried to add a StackPanel inside the AppBarButton tags with a SymbolIcon and a Textblock, but that didn't work either.
回答1:
We can edit the default style and template of AppBarButton
to achieve this. And I think there is no need to build a custom CommandOverflowPresenter
style.
Microsoft has provided XAML code for the default template, we can find at AppBarButton styles and templates. We can copy this style to Page.Resources
and give this style a key like x:Key="MyAppBarButtonStyle"
.
By default, the icon and text are placed vertically in the "ContentRoot" StackPanel
. We can change it like following to put them Horizontally.
<StackPanel x:Name="ContentRoot" MinHeight="{ThemeResource AppBarThemeCompactHeight}" Orientation="Horizontal">
<ContentPresenter x:Name="Content"
Margin="12,0,0,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
AutomationProperties.AccessibilityView="Raw"
Content="{TemplateBinding Icon}"
Foreground="{TemplateBinding Foreground}" />
<TextBlock x:Name="TextLabel"
Margin="12,0,12,0"
VerticalAlignment="Center"
FontFamily="{TemplateBinding FontFamily}"
FontSize="15"
Foreground="{TemplateBinding Foreground}"
Text="{TemplateBinding Label}"
TextAlignment="Center"
TextWrapping="Wrap" />
</StackPanel>
After this, we need to change the "Overflow" VisualState
like the article you mentioned to make sure the icon can be shown in secondary menu.
<VisualState x:Name="Overflow">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentRoot" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="OverflowTextLabel" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
Besides these, we may also need to change the HorizontalAlignment
and Width
property of AppBarButton
like following so that the StackPanel
can take full width of CommandOverflowPresenter
.
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Width" Value="Auto" />
Finally, we can use this style in SecondaryCommands
.
<CommandBar.SecondaryCommands>
<AppBarButton Style="{StaticResource MyAppBarButtonStyle}"
Click="AppBarButton_Click"
Icon="Like"
Label="Like" />
<AppBarButton Style="{StaticResource MyAppBarButtonStyle}"
Click="AppBarButton_Click"
Icon="Dislike"
Label="Dislike" />
</CommandBar.SecondaryCommands>
The complete style might like:
<Style x:Key="MyAppBarButtonStyle" TargetType="AppBarButton">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Width" Value="Auto" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="AppBarButton">
<Grid x:Name="Root"
MinWidth="{TemplateBinding MinWidth}"
MaxWidth="{TemplateBinding MaxWidth}"
Background="{TemplateBinding Background}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ApplicationViewStates">
<VisualState x:Name="FullSize" />
<VisualState x:Name="Compact">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextLabel" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Overflow">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentRoot" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="OverflowTextLabel" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="OverflowWithToggleButtons">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentRoot" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="OverflowTextLabel" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="OverflowTextLabel" Storyboard.TargetProperty="Margin">
<DiscreteObjectKeyFrame KeyTime="0" Value="38,0,12,0" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<PointerUpThemeAnimation Storyboard.TargetName="OverflowTextLabel" />
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextLabel" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="OverflowTextLabel" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
</ObjectAnimationUsingKeyFrames>
<PointerUpThemeAnimation Storyboard.TargetName="OverflowTextLabel" />
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListMediumBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextLabel" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="OverflowTextLabel" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
</ObjectAnimationUsingKeyFrames>
<PointerDownThemeAnimation Storyboard.TargetName="OverflowTextLabel" />
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextLabel" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="OverflowTextLabel" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="InputModeStates">
<VisualState x:Name="InputModeDefault" />
<VisualState x:Name="TouchInputMode">
<VisualState.Setters>
<Setter Target="OverflowTextLabel.Padding" Value="0,11,0,13" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackPanel x:Name="ContentRoot" MinHeight="{ThemeResource AppBarThemeCompactHeight}" Orientation="Horizontal">
<ContentPresenter x:Name="Content"
Margin="12,0,0,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
AutomationProperties.AccessibilityView="Raw"
Content="{TemplateBinding Icon}"
Foreground="{TemplateBinding Foreground}" />
<TextBlock x:Name="TextLabel"
Margin="12,0,12,0"
VerticalAlignment="Center"
FontFamily="{TemplateBinding FontFamily}"
FontSize="15"
Foreground="{TemplateBinding Foreground}"
Text="{TemplateBinding Label}"
TextAlignment="Center"
TextWrapping="Wrap" />
</StackPanel>
<TextBlock x:Name="OverflowTextLabel"
Margin="12,0,12,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
FontFamily="{TemplateBinding FontFamily}"
FontSize="15"
Foreground="{TemplateBinding Foreground}"
Padding="0,5,0,7"
Text="{TemplateBinding Label}"
TextAlignment="Left"
TextTrimming="Clip"
TextWrapping="NoWrap"
Visibility="Collapsed" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
来源:https://stackoverflow.com/questions/38284229/how-to-add-icons-to-secondarycommands-in-command-bar