样式控件:如何覆盖不同“VisualState"中的样式(PointerOver、Pressed...) [英] Styling controls: How to overwrite the styles in different 'VisualState's (PointerOver, Pressed, ...)

查看:24
本文介绍了样式控件:如何覆盖不同“VisualState"中的样式(PointerOver、Pressed...)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何处理悬停状态等?

可以为 Button 覆盖像 SystemControlHighlightBaseHighBrush 这样的画笔:

One could overwrite a brush like SystemControlHighlightBaseHighBrush for a Button:

<SolidColorBrush x:Key="SystemControlHighlightBaseHighBrush" Color="White" />

如果任何其他控件使用该画笔,它也会采用此值,这是不希望的.我发现的另一个选项是覆盖默认样式:

If any other control uses that brush, it also takes this value, which is not desired. The other option I found is to overwrite the default style:

<!-- 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 版本中的默认样式发生变化,该怎么办?

Here I would change the values in ObjectAnimationUsingKeyFrames. But what is if the default styling changes in an upcoming version of Windows?

目前我认为除了覆盖默认样式之外别无他法.也许人们可以覆盖一些事件并设置例如那里的边框颜色.但我认为并非所有事件都可用,您每次都必须编写自定义按钮.

Currently I see no other way than overwriting the default style. Perhaps one could overwrite some events and set e.g. the border color there. But I think there are not always all events available and you would have to write your custom button everytime.

在我看来,为了仅更改一个值而覆盖一个完整的样式似乎是错误的.您如何处理此类情况?

It looks somehow wrong to me to overwrite a complete style for changing only one value. How do you handle such cases?

推荐答案

TL;DR:是的,更改完整模板(而非样式)是最常用的场景.

TL;DR: Yes, changing the complete template (not style) is the most used scenario.

这里需要考虑不同的点:

There are different points to consider here:

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

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

So my first option would be to define a new theme for your application and indeed overwrite the SystemControlHighlightBaseHighBrush and other ThemeResource resources required to accomplish your new branding.

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

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

If for some valid reason you don't want all controls using the ThemeResource to change to your new theme, you will have to overwrite the complete control template (as the template is one block and thus an all or nothing). There is no need to overwrite all other property setters (like Foreground, Background, Padding, ... in your example).

如果您很幸运,您尝试更改的属性是模板化属性,您可以简单地使用单个属性设置器来修复您的布局.

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

The downside with this approach is indeed that future versions of the SDK can change the template of a given control. An example of this are the GridView/GridViewItem styles between Windows 8/8.1 and 10. So far there has mostly been a backward compatibility on styles, meaning your app will continue to work but might not be in line with the latest layout guidelines or miss some performance improvements. It's therefor 'best practice' to re-apply custom layout changes on the newest templates (if time permits).

肮脏"的解决方案是入侵"可视化树以在运行时更改属性(基于事件,...).但这也不会阻止您在未来的 SDK 更新中可能发生重大更改,因此我什至不认为这是一个有效的选择.

A 'dirty' solution is 'hacking' into the Visual Tree to change properties at runtime (based on events, ...). But this won't prevent you from possible breaking changes on future SDK updates either, so I wouldn't even consider this as a valid option.

  • 使用自定义控件

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

The final approach is going with a custom control, define your own template (again the same problem with newer SDK versions) or use the default template and override OnApplyTemplate and tweak the property you'd like to change by getting it from the Visual Tree. But same remarks apply here that a future SDK version might drop the control/state in your tree and break your code.

结论:无论您选择哪个选项,未来的 SDK 版本都有可能破坏您的实现.

Conclusion: either option you choose, there's a possibility future SDK versions will break your implementation.

这篇关于样式控件:如何覆盖不同“VisualState"中的样式(PointerOver、Pressed...)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆