【Win10】让 AppBarButton 支持更复杂的 Icon 内容

最近有一个需求,需要制作这么一个 AppBarButton:

QQ截图20151102162629

这个 AppBarButton 的 Icon 是一个评论框图标里面再显示评论数(大于 99 条则显示 99+)。其中评论数是通过数据绑定得来的。

要单独显示这个评论框图标或者单独显示评论数都不是难题,然而要同时显示这两者就成了一个大问题了,因为 AppBarButton 的 Icon 属性只能设置一个。再看看 Icon 属性的类型,是 IconElement 这个类。但是,这个类的构造函数是内部的,我们也没法继承它。那么,从 Icon 属性上入手是不可能了。

但是,要注意到,绝大部分的控件都是有模板的,然后可以修改的。对于 AppBarButton,是不是也这样呢?答案是肯定的。

在 MSDN 上,我们可以查阅到 AppBarButton 的默认样式和模板:https://msdn.microsoft.com/zh-cn/library/windows/apps/mt299105.aspx

<!-- Default style for Windows.UI.Xaml.Controls.AppBarButton -->
<Style TargetType="AppBarButton">
  <Setter Property="Background" Value="Transparent"/>
  <Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}"/>
  <Setter Property="HorizontalAlignment" Value="Left"/>
  <Setter Property="VerticalAlignment" Value="Top"/>
  <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
  <Setter Property="FontWeight" Value="Normal"/>
  <Setter Property="Width" Value="68"/>
  <Setter Property="UseSystemFocusVisuals" Value="True" />
  <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="Collapsed"/>
                  </ObjectAnimationUsingKeyFrames>
                  <ObjectAnimationUsingKeyFrames Storyboard.TargetName="OverflowTextLabel" Storyboard.TargetProperty="Visibility">
                    <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                  </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,11,0,13"/>
                  </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 SystemControlDisabledBaseLowBrush}"/>
                  </ObjectAnimationUsingKeyFrames>
                  <ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextLabel" Storyboard.TargetProperty="Foreground">
                    <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}"/>
                  </ObjectAnimationUsingKeyFrames>
                  <ObjectAnimationUsingKeyFrames Storyboard.TargetName="OverflowTextLabel" Storyboard.TargetProperty="Foreground">
                    <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}"/>
                  </ObjectAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>
            </VisualStateGroup>
          </VisualStateManager.VisualStateGroups>

          <StackPanel x:Name="ContentRoot" MinHeight="{ThemeResource AppBarThemeCompactHeight}">
            <ContentPresenter
                x:Name="Content"
                Height="20"
                Margin="0,14,0,4"
                Content="{TemplateBinding Icon}"
                Foreground="{TemplateBinding Foreground}"
                HorizontalAlignment="Stretch"
                AutomationProperties.AccessibilityView="Raw"/>
            <TextBlock
                x:Name="TextLabel"
                Text="{TemplateBinding Label}"
                Foreground="{TemplateBinding Foreground}"
                FontSize="12"
                FontFamily="{TemplateBinding FontFamily}"
                TextAlignment="Center"
                TextWrapping="Wrap"
                Margin="0,0,0,6"/>
          </StackPanel>

          <TextBlock
              x:Name="OverflowTextLabel"
              Text="{TemplateBinding Label}"
              Foreground="{TemplateBinding Foreground}"
              FontSize="15"
              FontFamily="{TemplateBinding FontFamily}"
              TextAlignment="Left"
              TextTrimming="Clip"
              TextWrapping="NoWrap"
              HorizontalAlignment="Stretch"
              VerticalAlignment="Center"
              Margin="12,11,0,13"
              Visibility="Collapsed"/>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

仔细看一下这个模板,我们可以发现这么一句:

Content="{TemplateBinding Icon}"

我们尝试一下将 Icon 修改为 Content。(Content 属性是 AppBarButton 从 Button 类继承得来的,但是 AppBarButton 它自身并没有使用到这个属性。)

然后编写 XAML 测试下:

<CommandBar>
    <AppBarButton Style="{StaticResource MyAppBarButtonStyle}"
                             Label="评论">
        <AppBarButton.Content>
            <Grid>
                <FontIcon Glyph="&#xE8BD;"
                                 FontFamily="Segoe MDL2 Assets"
                                 HorizontalAlignment="Center"
                                 VerticalAlignment="Center" />
                <TextBlock Text="99+"
                                   HorizontalAlignment="Center"
                                   VerticalAlignment="Center"
                                   FontSize="9"
                                   RenderTransformOrigin="0.5,0.5">
                    <TextBlock.RenderTransform>
                        <TranslateTransform Y="-2.5" />
                    </TextBlock.RenderTransform>
                </TextBlock>
            </Grid>
        </AppBarButton.Content>
    </AppBarButton>
</CommandBar>

运行后,你应该可以看到文章开头的效果了。

 

最后,当然是稍微封装下了,因为 AppBarButton 是能够继承的。由于没啥技术含量-_-|||,这里就大家自己弄了。

posted @ 2015-11-02 18:30  h82258652  阅读(1072)  评论(0编辑  收藏  举报