样式控件:如何覆盖不同的VisualState中的样式(PointerOver,Pressed,...)

时间:2016-11-17 13:15:08

标签: xaml uwp windows-10-universal

如何处理悬停状态等等?

可以为SystemControlHighlightBaseHighBrush

覆盖Button之类的画笔
<SolidColorBrush x:Key="SystemControlHighlightBaseHighBrush" Color="White" />

如果任何其他控件使用该画笔,它也会使用此值,这是不需要的。我找到的另一个选项是覆盖默认样式:

<!-- Default style for Windows.UI.Xaml.Controls.Button -->
<Style TargetType="Button">
    <Setter Property="Background" Value="{ThemeResource SystemControlBackgroundBaseLowBrush}" />
    <Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}"/>
    <Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundTransparentBrush}" />
    <Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" />
    <Setter Property="Padding" Value="8,4,8,4" />
    <Setter Property="HorizontalAlignment" Value="Left" />
    <Setter Property="VerticalAlignment" Value="Center" />
    <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
    <Setter Property="FontWeight" Value="Normal" />
    <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
    <Setter Property="UseSystemFocusVisuals" Value="True" />
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="Button">
          <Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
            <VisualStateManager.VisualStateGroups>
              <VisualStateGroup x:Name="CommonStates">
                <VisualState x:Name="Normal">
                  <Storyboard>
                    <PointerUpThemeAnimation Storyboard.TargetName="RootGrid" />
                  </Storyboard>
                </VisualState>
                <VisualState x:Name="PointerOver">
                  <Storyboard>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                       Storyboard.TargetProperty="BorderBrush">
                      <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseMediumLowBrush}" />
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                       Storyboard.TargetProperty="Foreground">
                      <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseHighBrush}" />
                    </ObjectAnimationUsingKeyFrames>
                    <PointerUpThemeAnimation Storyboard.TargetName="RootGrid" />
                  </Storyboard>
                </VisualState>
                <VisualState x:Name="Pressed">
                  <Storyboard>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid"
                                                       Storyboard.TargetProperty="Background">
                      <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlBackgroundBaseMediumLowBrush}" />
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                       Storyboard.TargetProperty="BorderBrush">
                      <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightTransparentBrush}" />
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                       Storyboard.TargetProperty="Foreground">
                      <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseHighBrush}" />
                    </ObjectAnimationUsingKeyFrames>
                    <PointerDownThemeAnimation Storyboard.TargetName="RootGrid" />
                  </Storyboard>
                </VisualState>
                <VisualState x:Name="Disabled">
                  <Storyboard>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid"
                                                       Storyboard.TargetProperty="Background">
                      <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlBackgroundBaseLowBrush}" />
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                       Storyboard.TargetProperty="Foreground">
                      <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                       Storyboard.TargetProperty="BorderBrush">
                      <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledTransparentBrush}" />
                    </ObjectAnimationUsingKeyFrames>
                  </Storyboard>
                </VisualState>
              </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
            <ContentPresenter x:Name="ContentPresenter"
                              BorderBrush="{TemplateBinding BorderBrush}"
                              BorderThickness="{TemplateBinding BorderThickness}"
                              Content="{TemplateBinding Content}"
                              ContentTransitions="{TemplateBinding ContentTransitions}"
                              ContentTemplate="{TemplateBinding ContentTemplate}"
                              Padding="{TemplateBinding Padding}"
                              HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                              VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                              AutomationProperties.AccessibilityView="Raw"/>
          </Grid>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
</Style>

在这里,我将更改ObjectAnimationUsingKeyFrames中的值。但是,如果即将推出的Windows版本中的默认样式发生了变化,该怎么办?

目前,除了覆盖默认样式外,我没有别的办法。或许可以覆盖一些事件并设置例如那边的边框颜色。但我认为并非所有活动都可用,您每次都必须编写自定义按钮。

对于我来说,覆盖一个完整的样式以仅更改一个值看起来有些不对。你是如何处理这种情况的?

1 个答案:

答案 0 :(得分:1)

TL; DR:是的,更改完整模板(不是样式)是最常用的方案。

这里有不同的要点:

  • 您希望所有控件在整个应用程序中具有一致的布局。

因此,我的第一个选择是为您的应用定义新的主题,并确实覆盖完成新品牌所需的SystemControlHighlightBaseHighBrush和其他ThemeResource资源。

  • 您只需要一个控件来更改布局。

如果出于某种正当理由,您不希望使用ThemeResource的所有控件更改为新主题,则必须覆盖整个控件模板(因为模板是一个块,因此全有或全无)。无需覆盖所有其他属性设置器(例如前景,背景,填充......)。

如果您非常幸运,您尝试更改的属性是模板化属性,您只需使用一个属性设置器来修复您的布局。

这种方法的缺点确实是SDK的未来版本可以更改给定控件的模板。一个例子是Windows 8 / 8.1和10之间的GridView / GridViewItem样式。到目前为止,大多数样式都向后兼容,这意味着你的应用程序将继续工作,但可能不符合最新的布局指南或错过一些性能改进。因此,最佳实践&#39;在最新模板上重新应用自定义布局更改(如果时间允许)。

A&#39;脏&#39;解决方案是&#39; hacking&#39;进入Visual Tree以在运行时更改属性(基于事件,...)。但这不会阻止您对未来的SDK更新进行可能的更改,因此我甚至不认为这是一个有效的选项。

  • 使用自定义控件

最后一种方法是使用自定义控件,定义您自己的模板(对于较新的SDK版本也是同样的问题)或使用默认模板并覆盖OnApplyTemplate并调整您想要的属性通过从Visual Tree获取它来改变。但同样的说法是,未来的SDK版本可能会删除树中的控件/状态并破坏您的代码。

结论:您选择的任一选项,未来的SDK版本都可能会破坏您的实施。