Eduardo Serrano
Eduardo Serrano

Reputation: 21

Windows Store App 8.1 - Creating AppBarButton Styles that accept a Path

I'm trying to create a style for an AppBarButton. What I would like to do is change some colours in the pressed state and use a Path as the content. Since I've had no problem with the colouring. I would like to focus on the using a Path as the content part. Instead of doing something like:

<AppBarButton Label="PathIcon">
    <AppBarButton.Icon>
        <PathIcon Data="F1 M 20,20L 24,10L 24,24L 5,24"/>
    </AppBarButton.Icon>
</AppBarButton>

I would like to do something like:

<AppBarButton Label="PathIcon" Style="{StaticResource MyAppBarButtonStyle1}"/>

So I've edited a copy of the AppBarButton which got me something like this:

  <Style x:Key="MyAppBarButtonStyle" TargetType="AppBarButton">
        <Setter Property="Foreground" Value="{ThemeResource AppBarItemForegroundThemeBrush}"/>
        <Setter Property="VerticalAlignment" Value="Top"/>
        <Setter Property="HorizontalAlignment" Value="Left"/>
        <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
        <Setter Property="FontWeight" Value="Normal"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="AppBarButton">
                    <Grid x:Name="RootGrid" Background="Transparent" Width="100">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="ApplicationViewStates">
                                <VisualState x:Name="FullSize"/>
                                <VisualState x:Name="Compact">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="TextLabel">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Width" Storyboard.TargetName="RootGrid">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="60"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal"/>
                                <VisualState x:Name="PointerOver">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="BackgroundEllipse">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource AppBarItemPointerOverBackgroundThemeBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="Content">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource AppBarItemPointerOverForegroundThemeBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Stroke" Storyboard.TargetName="OutlineEllipse">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource AppBarItemForegroundThemeBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="BackgroundEllipse">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource AppBarItemForegroundThemeBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="Content">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource AppBarItemPressedForegroundThemeBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Stroke" Storyboard.TargetName="OutlineEllipse">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource AppBarItemDisabledForegroundThemeBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="Content">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource AppBarItemDisabledForegroundThemeBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="TextLabel">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource AppBarItemDisabledForegroundThemeBrush}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="FocusStates">
                                <VisualState x:Name="Focused">
                                    <Storyboard>
                                        <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FocusVisualWhite"/>
                                        <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FocusVisualBlack"/>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Unfocused"/>
                                <VisualState x:Name="PointerFocused"/>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <StackPanel Margin="0,14,0,13" VerticalAlignment="Top">
                            <Grid HorizontalAlignment="Center" Height="40" Margin="0,0,0,5" Width="40">
                                <Ellipse x:Name="BackgroundEllipse" Fill="{ThemeResource AppBarItemBackgroundThemeBrush}" Height="40" UseLayoutRounding="False" Width="40"/>
                                <Ellipse x:Name="OutlineEllipse" Height="40" Stroke="{ThemeResource AppBarItemForegroundThemeBrush}" StrokeThickness="2" UseLayoutRounding="False" Width="40"/>
                                <ContentPresenter x:Name="Content" AutomationProperties.AccessibilityView="Raw" Content="{TemplateBinding Icon}" Foreground="{TemplateBinding Foreground}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>                            
                            </Grid>
                            <TextBlock x:Name="TextLabel" Foreground="{ThemeResource AppBarItemForegroundThemeBrush}" FontSize="12" FontFamily="{TemplateBinding FontFamily}" TextAlignment="Center" TextWrapping="Wrap" Text="{TemplateBinding Label}" Width="88"/>
                        </StackPanel>
                        <Rectangle x:Name="FocusVisualWhite" IsHitTestVisible="False" Opacity="0" StrokeDashOffset="1.5" StrokeEndLineCap="Square" Stroke="{ThemeResource FocusVisualWhiteStrokeThemeBrush}" StrokeDashArray="1,1"/>
                        <Rectangle x:Name="FocusVisualBlack" IsHitTestVisible="False" Opacity="0" StrokeDashOffset="0.5" StrokeEndLineCap="Square" Stroke="{ThemeResource FocusVisualBlackStrokeThemeBrush}" StrokeDashArray="1,1"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Then I changed all the colours in the above template (which isn't done in this example) and did this:

<Style x:Key="MyAppBarButtonStyle1" TargetType="AppBarButton" BasedOn="{StaticResource LogInAppBarButtonStyle}">
    <Setter Property="Content">
        <Setter.Value>
            <PathIcon Data="F1 M 20,20L 24,10L 24,24L 5,24"/>
        </Setter.Value>
    </Setter>
</Style>

However this did not work. Nothing shows in the content of the AppBarButton. Furthermore, you might have noticed that the MyAppBarButtonStyle1 is setting the Content property instead of the Icon property. This was because if I try to set the Icon property I get an weird exception when I open the page containing the AppBarButton:

Error HRESULT E_FAIL has been returned from a call to a COM component. (???...)

Also note that the first piece of code that sets the Icon property to a PathIcon works just fine, trying to move it to a style is where I'm failing.

So can anyone point me in the right direction? How to create AppBarButton styles using a Path as its content?

Thank you.

Upvotes: 0

Views: 2886

Answers (1)

Eduardo Serrano
Eduardo Serrano

Reputation: 21

I've gotten lucky in figuring this one out. I was fiddling with metro studio. When switching to the xaml view there is an option named "winrt appbar" which shows the following:

<Style x:Key="PathBasedAppBarButtonStyle" BasedOn="{StaticResource AppBarButtonStyle}" TargetType="ButtonBase">
     <Setter Property="ContentTemplate">
         <Setter.Value>
             <DataTemplate>
                 <Path Width="18" Height="18" 
             Stretch="Uniform" HorizontalAlignment="Center" VerticalAlignment="Center"
                       Margin="0 0 2 0" RenderTransformOrigin="0.5,0.5" 
             Fill="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=TemplatedParent}}" 
             Data="{Binding Path=Content, RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
             </DataTemplate>
         </Setter.Value>
     </Setter>
</Style>


<Style x:Key="Add-NewAppBarButtonStyle" BasedOn="{StaticResource PathBasedAppBarButtonStyle}" TargetType="ButtonBase">
      <Setter Property="AutomationProperties.Name" Value="Add-New"/>
      <Setter Property="AutomationProperties.AutomationId" Value="Add-NewAppBarButton"/>
      <Setter Property="Content" Value="M19.833,0L32.5,0 32.5,19.833999 52.334,19.833999 52.334,32.500999 32.5,32.500999 32.5,52.333 19.833,52.333 19.833,32.500999 0,32.500999 0,19.833999 19.833,19.833999z"/>
</Style>

This is exactly what I was trying to do. The PathBasedAppBarButtonStyle enables me to create styles based on it whilst changing the Path's Data.

I did change the above code slightly:

1) I changed the TargetType to AppBarButton

2) To get the AppBarButtonStyle I copied it from C:\Program Files (x86)\Windows Kits\8.1\Include\winrt\xaml\design\generic.xaml (under )

So now I can do

<AppBarButton Label="PathIcon" Style="{StaticResource MyAppBarButtonStyle1}"/>

as long as the MyAppBarButtonStyle1 is a style based on PathBasedAppBarButtonStyle (like the Add-NewAppBarButtonStyle)

Hope this helps newcomers like me,

Regards

Upvotes: 2

Related Questions