Thursday, May 2, 2013

Custom TopAppBarButtonStyle to mimic the Windows 8 Weather app TopAppBar

The Windows 8 Weather app uses a top app bar for flat (rather than hierarchical) navigation between Home, Places, and World Weather pages. It appears at the top of the page and uses square controls rather than the rounded ones used by the bottom app bar for commands.

With a C# and XAML project you can get started with the bottom app bar pretty quickly using the Styles derived from

AppBarButtonStyle
in the /Common/StandardStyles.xaml that comes with most new projects. There isn't however an equivalent style for TopAppBarButtonStyle that can be used in the TopAppBar.

I've started down the path of defining my own style, but didn't complete it as I decided against used the navigation bar with an otherwise hierarchical app. It is still very much a work in progress, but placed here for when I need it again.

In StandardStyles.xaml

    <Style x:Key="TopAppBarButtonStyle" TargetType="Button">
        <Setter Property="Width" Value="150"/>
        <Setter Property="Height" Value="100"/>
        <Setter Property="Background" Value="#FF3F3F3F" />
        <Setter Property="BorderBrush" Value="#FF3F3F3F" />
        <Setter Property="FontFamily" Value="Segoe UI Symbol"/>
        <Setter Property="FontWeight" Value="Normal"/>
        <Setter Property="FontSize" Value="28"/>
        <Setter Property="HorizontalContentAlignment" Value="Left"/>
        <!--HorizontalAlignment="Right"-->
        <Setter Property="Template">
            <Setter.Value>

                <ControlTemplate TargetType="Button">
                    <Grid>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal" />
                                <VisualState x:Name="PointerOver">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Border" Storyboard.TargetProperty="Background">
                                            <!--<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonPointerOverBackgroundThemeBrush}" />-->
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="#FF242424" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonPointerOverForegroundThemeBrush}" />
                                            <!--<DiscreteObjectKeyFrame KeyTime="0" Value="#FF242424" />-->
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Border" Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonPressedBackgroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonPressedForegroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Border" Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonDisabledBackgroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Border" Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonDisabledBorderThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonDisabledForegroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="FocusStates">
                                <VisualState x:Name="Focused">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="FocusVisualWhite" Storyboard.TargetProperty="Opacity" To="1" Duration="0" />
                                        <DoubleAnimation Storyboard.TargetName="FocusVisualBlack" Storyboard.TargetProperty="Opacity" To="1" Duration="0" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Unfocused" />
                                <VisualState x:Name="PointerFocused" />
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Margin="3" Padding="0,10,0,0">
                            <StackPanel HorizontalAlignment="Left" Width="140" Margin="10,0">
                                <ContentPresenter x:Name="ContentPresenter" Content="{TemplateBinding Content}" ContentTransitions="{TemplateBinding ContentTransitions}" ContentTemplate="{TemplateBinding ContentTemplate}" Margin="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                                <TextBlock
                                    x:Name="TextLabel"
                                    Text="{TemplateBinding AutomationProperties.Name}"
                                    Foreground="{StaticResource AppBarItemForegroundThemeBrush}"
                                    Margin="0,0,2,0"
                                    FontSize="14"
                                    TextAlignment="Left"
                                    MaxHeight="32"
                                    TextTrimming="WordEllipsis"
                                    Style="{StaticResource BasicTextStyle}"/>
                            </StackPanel>
                        </Border>
                        <Rectangle x:Name="FocusVisualWhite" IsHitTestVisible="False" Stroke="{StaticResource FocusVisualWhiteStrokeThemeBrush}" StrokeEndLineCap="Square" StrokeDashArray="1,1" Opacity="0" StrokeDashOffset="1.5" />
                        <Rectangle x:Name="FocusVisualBlack" IsHitTestVisible="False" Stroke="{StaticResource FocusVisualBlackStrokeThemeBrush}" StrokeEndLineCap="Square" StrokeDashArray="1,1" Opacity="0" StrokeDashOffset="0.5" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style x:Key="HomeTopAppBarButtonStyle" TargetType="Button" BasedOn="{StaticResource TopAppBarButtonStyle}">
        <Setter Property="AutomationProperties.AutomationId" Value="HomeTopAppBarButtonStyle"/>
        <Setter Property="AutomationProperties.Name" Value="Home"/>
        <Setter Property="Content" Value=""/>
    </Style>

In the page:

    <common:LayoutAwarePage.TopAppBar>
        <AppBar Height="150">
            <StackPanel  Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Left">

                <Button x:Name="homePageButton" 
                    Click="HomeButtonClick"
                     Style="{StaticResource HomeTopAppBarButtonStyle}"/>
            </StackPanel>
        </AppBar>
    </common:LayoutAwarePage.TopAppBar>

See Also: