在 UWP 中,可以通过给空间直接设置属性或在 Style 中设置属性来定制空间的样式;不过这样的样式定义十分有限,比如按钮按下时的样式就没法儿设置。当然可以通过修改 Template 来设置控件的样式,然而 UWP 中控件的样式代码实在是太多太复杂了,还不容易从 Blend 中复制了大量代码出来改,下个版本样式又不一样,于是我们就丢了不少功能。

本文将介绍 UWP 轻量级样式定义(Lightweight styling),你既不用写太多代码,又能获得更多的样式控制。


轻量级样式定义

看一段简单的代码,你一定能立刻明白本文想说的是什么。

<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="ButtonBackground" Color="Transparent"/>
<SolidColorBrush x:Key="ButtonForeground" Color="#dd5145"/>
<SolidColorBrush x:Key="ButtonBorderBrush" Color="#dd5145"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Page.Resources>

本段代码摘抄自 XAML Lightweight styling - UWP app developer - Microsoft Docs


▲ 按钮的颜色定制

以上代码可以写在 Page 中,即可在 Page 范围内获得这些主题资源的重写。当然,如果需要更大范围,可以考虑去 App 类中重写。

官网上举例的这种类型的样式定义其实普通的 Style 也能很容易实现的,真正厉害的是 Style 里设置不了的那些鼠标滑过颜色和鼠标按下颜色。于是,我们额外添加一些代码:

<SolidColorBrush x:Key="ButtonBackground" Color="Transparent"/>
<SolidColorBrush x:Key="ButtonForeground" Color="#dd5145"/>
<SolidColorBrush x:Key="ButtonBorderBrush" Color="#dd5145"/>
<SolidColorBrush x:Key="ButtonBackgroundPointerOver" Color="#10dd5145"/>
<SolidColorBrush x:Key="ButtonForegroundPointerOver" Color="#ffcd44"/>
<SolidColorBrush x:Key="ButtonBorderBrushPointerOver" Color="#ffcd44"/>
<SolidColorBrush x:Key="ButtonBackgroundPressed" Color="#10ca5100"/>
<SolidColorBrush x:Key="ButtonForegroundPressed" Color="#ca5100"/>
<SolidColorBrush x:Key="ButtonBorderBrushPressed" Color="#ca5100"/>

现在我们只是设置一些颜色值即修改了按钮在多种状态下的外观。而且在按下的过程中,还保留了按钮按下时的倾斜效果。


▲ 按钮更多的颜色定制

相比于 Template -> Edit Copy 这种重量级的样式与模板定义,在保证足够的样式定义的情况下,代码量是不是少了非常多了呢?

如何找到控件支持的主题资源

前面我们知道了如何定制轻量级样式,但实际做 UI 的时候,我怎么知道有哪些样式主题资源的值可以使用呢?

一种方法是直接看微软官方文档,比如这里 XAML theme resources;你可以在这篇文章中找到很多通用的主题资源的 Key 用来重写。不过实际上由于 Windows Community Toolkit 以及各种第三方控件库的存在,所以没有什么文档是可以把这些 Key 写全的;所以更重要的方法是我们能自己找到有哪些 Key 可以使用。

找到 Key 的方法和定义一个全新的 Style / Template 一样,都可以通过 Visual Studio 的设计器视图(或者 Blend)实现。

第一步:前往 Visual Studio 设计器视图


▲ Visual Studio 设计器视图

第二步:在其中一个你想定制样式的控件上 右键 -> 编辑模板 -> 编辑副本


▲ 编辑模板

特别注意,如果你发现你的 “编辑副本” 是灰色的,说明你已经定制过样式了。将你已经定制的样式删除后,就可以再编辑副本了。


▲ 灰色的 “编辑副本”

第三步:寻找你感兴趣的主题资源的 Key,记下来准备定义

在编辑副本后,你可以在副本的代码中找到按钮的原生样式定义。比如一个按钮的样式是这样的:

<Style x:Key="ButtonStyle1" TargetType="Button">
<Setter Property="Background" Value="{ThemeResource ButtonBackground}"/>
<Setter Property="Foreground" Value="{ThemeResource ButtonForeground}"/>
<Setter Property="BorderBrush" Value="{ThemeResource ButtonBorderBrush}"/>
<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="{StaticResource UseSystemFocusVisuals}"/>
<Setter Property="FocusVisualMargin" Value="-3"/>
<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="RootGrid" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundPointerOver}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushPointerOver}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundPointerOver}"/>
</ObjectAnimationUsingKeyFrames>
<PointerUpThemeAnimation Storyboard.TargetName="RootGrid"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundPressed}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushPressed}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundPressed}"/>
</ObjectAnimationUsingKeyFrames>
<PointerDownThemeAnimation Storyboard.TargetName="RootGrid"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundDisabled}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushDisabled}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundDisabled}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter x:Name="ContentPresenter" AutomationProperties.AccessibilityView="Raw" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentTransitions="{TemplateBinding ContentTransitions}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

从中我们可以找到这些可以定义的主题资源 Key:

  • ButtonBackground
  • ButtonForeground
  • ButtonBorderBrush
  • ButtonBorderThemeThickness
  • ContentControlThemeFontFamily
  • ControlContentThemeFontSize
  • ButtonBackgroundPointerOver
  • ButtonBorderBrushPointerOver
  • ButtonForegroundPointerOver
  • ButtonBackgroundPressed
  • ButtonBorderBrushPressed
  • ButtonForegroundPressed
  • ButtonBackgroundDisabled
  • ButtonBorderBrushDisabled
  • ButtonForegroundDisabled

第四步:轻量级样式定义

请先删除这份副本样式,这样你就可以进行 “轻量级样式定义” 了。代码量相比于上面这份完整样式可以少非常多。

UWP 轻量级样式定义(Lightweight Styling)的更多相关文章

  1. CSS样式定义的优先级顺序总结

    CSS样式定义的优先级顺序总结 层叠优先级是: 浏览器缺省 < 外部样式表 < 内部样式表 < 内联样式 其中样式表又有: 类选择器 < 类派生选择器 < ID选择器 & ...

  2. mathtype样式系统使用技巧-通过样式定义来更改方程中的字体

    本教程中,我们主要介绍MathType Desktop的样式系统.演示如何通过更改样式定义来更改方程中的字体.通过样式可以快速轻松地实现我们所需的公式格式,并统一所有公式的样式. 我们以如下公式来作为 ...

  3. JavaScript获取非行间样式/定义样式

    html节点的样式分为以下几种 (1)浏览器默认样式 (2)引用样式(引用外部css文件的样式.style标签内定义的样式) 引用外部css样式:<link rel="styleshe ...

  4. Silverlight样式定义

    方法一.定义在控件内部 <Canvas Background="Red" Height="100" HorizontalAlignment="L ...

  5. console 中的格式化打印(占位符),和样式定义

    格式化打印 Gecko 9.0 (Firefox 9.0 / Thunderbird 9.0 / SeaMonkey 2.6) 首次发布对string substitutions的支持.你可以在传递给 ...

  6. js获取非行间样式/定义样式

    <!--DOCTYPE html--> <html> <head> <meta charset="utf-8" /> <sty ...

  7. table的样式定义

    table的cellpadding和cellpadding我们经常会用如下的方式来清除默认样式: <table cellspacing="0" cellpadding=&qu ...

  8. UWP appButtonBar样式

    UWP 的appButtonBar使用<AppBarButton Icon = "Next" Label = "Next" /> Icon是 Sym ...

  9. 28. 表单css样式定义格式

    form>table>tbody>tr>td{padding:5px;font-size:14px;font-family:"Microsoft YaHei" ...

随机推荐

  1. cocos代码研究(21)Widget子类TextField学习笔记

    基础理论 一个接受用户输入的widget. 输入文本的渲染基于TextFieldTTF. 如果你想用系统控制行为,请使用EditBox来替代.继承自 Widget. 代码实践 //与占位符有关void ...

  2. org.apache.ibatis.exceptions.TooManyResultsException的异常排查过程

    在查阅测试环境业务日志中的ERROR级别的日志时,发现了有一个Mybatis相关的异常错误org.apache.ibatis.exceptions.TooManyResultsException: E ...

  3. SQL学习笔记四(补充-1)之MySQL单表查询

    阅读目录 一 单表查询的语法 二 关键字的执行优先级(重点) 三 简单查询 四 WHERE约束 五 分组查询:GROUP BY 六 HAVING过滤 七 查询排序:ORDER BY 八 限制查询的记录 ...

  4. img = img1*mask + img2*(1-mask) How do that ?

    原文地址:http://answers.opencv.org/question/160599/img-img1mask-img21-mask-how-do-that/ 如何提高一个简单操作的速度?最后 ...

  5. Eclipse插件Fat Jar

    1.安装 1)Eclipse在线更新方法 Help > Install New Software > Add, name:Fat Jar location:http://kurucz-gr ...

  6. C#中标准Dispose模式的实现(转载)

    需要明确一下C#程序(或者说.NET)中的资源.简单的说来,C#中的每一个类型都代表一种资源,而资源又分为两类: 托管资源:由CLR管理分配和释放的资源,即由CLR里new出来的对象: 非托管资源:w ...

  7. spark + cassandra +postgres +codis 大数据方案

    1.环境: 1.1.cassandra 集群: 用于日志数据存储 1.2.spark集群: 用户后期的实时计算及批处理 1.3.codis 集群: 用于缓存一些基本数据如IP归属地,IP经纬度等,当日 ...

  8. [Checking for libstdc++-4.4.4-13.el6-i686; Not found. Failed] 的解决。

    单纯 yum install libstdc++-4.4.4.i686 是不行的. 应该安装 yum install libstdc++-devel.i686 顺带就能装上需要的lib 真够变态的. ...

  9. Learn Rails5.2- ActiveRecord: Migration , spring的使用(不兼容的解决办法)

    偶然一次: 运行rails generate停止不动,网上查找答案,可能是bundle update 之后 spring 版本变化了,和正在运行的 spring 实例不兼容. Spring导致的同样的 ...

  10. Learn Rails5.2- ActiveRecord: sqlite3的用法, Query查询语法。乐观锁和悲观锁案例,查询语法includes(), 多态关联,destory和delete, Scope, Validats, Migrations

    rails generate model photo title:string album:references 这会产生一个album_id列,当建立belongs_to关联时,需要用到. refe ...