Avalonia UI 中 Styles 与 ControlTheme 的区别
目录
介绍
在 Avalonia UI 中有几种概念 Theme Style ControlTheme,从WPF转过来的时候对于 ControlTheme 跟 Theme 的区别是什么呢? 为什么Style跟我们的WPF的Style的效果不太一样? Trigger 也没了?
首选需要说的是, Theme、Style、ControlTheme 都是继承自 IStyle 也就是说他们都是 样式(Style), 但是他们之间有一些差异.
这里介绍一下我个人如何理解这三种 IStyle
Theme暂且理解为全局主题(Global Theme)Style暂且理解为局部主题(Local Theme)ControlTheme暂且理解为控件样式 (Control Style, 类似WPF中定义控件Style以及Template)
使用方式
全局主题 (Global Theme)
// App.xaml
<Application xmlns="https://github.com/avaloniaui"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
<Application.Styles>
<FluentTheme /> // 这里的Theme 其实也是Style
</Application.Styles>
</Application>
局部主题 (Local Theme)
如果将 Style 方式在 Window或者UserControl或者Control下即为局部主题
<Window>
<Window.Styles>
<!-- Common button properties -->
<Style Selector="Button">
<Setter Property="Margin" Value="10" />
<Setter Property="MinWidth" Value="200" />
<Setter Property="Height" Value="50" />
<Setter Property="HorizontalContentAlignment" Value="Right" />
<Setter Property="VerticalContentAlignment" Value="Bottom" />
<Style Selector="^:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="Green" />
</Style>
</Style>
</Window.Styles>
// ...
</Window>
控件主题 (ControlTheme)
注意: 这里的 ControlTheme 是放置在 Window.Resource 下
<Window.Resource>
<ControlTheme x:Key="{x:Type Button}" TargetType="Button">
<Setter Property="Background" Value="#C3C3C3" />
<Setter Property="FontFamily" Value="Arial" />
<Setter Property="FontSize" Value="14" />
<Setter Property="Height" Value="100" />
<Setter Property="Template">
<ControlTemplate>
// ...
</ControlTemplate>
</Setter>
<Style Selector="^:pointerover">
<Setter Property="Background" Value="red" />
</Style>
</ControlTheme>
</Window.Resource>
问题描述
从使用方式上看 Global Theme 与 Local Theme 是一样的, 都是放置在 Styles 属性下. 问题的关键是:
Styles下的Theme与Resource下的ControlTheme有什么区别?Styles跟ControlTheme同样可以重写Template, 那我要选哪个来重写Template?
问题分析
在下文我将 Styles下的Theme或Style称为 Styles, 将Resources下的ControlTheme成为ControlTheme, 方便大家理解.
问题1 区别
按我个人的理解来看,这是属于两种UI设计模式.
Styles类似于CSS样式表操作,针对在应用范围内的所有选择的元素的Style都将被应用.ControlTheme是类似与WPF的 Style, 除了默认ControlTheme, 其他ControlTheme都需要指定Key,相对独立。
问题2 重写Template用 Styles 还是 ControlTheme?
两种模式都可以写, ControlTheme 是从 v11 版本引入的. 主要是为了解决 Styles 之间的隔离性. 如:
<Style Selector="Button"> // Default Style
<Setter Property="HorizontalContentAlignment" Value="Right" />
<Setter Property="VerticalContentAlignment" Value="Bottom" />
</Style>
// 两个Button的Style有关联关系
<Style Selector="Button.NewStyle"> // 对 Default Style 的修改都有可能影响其他Style
<Setter Property="HorizontalContentAlignment" Value="Left" />
// <Setter Property="VerticalAlignment" Value="Bottom" /> // 来此Default Style
</Style>
试想这样一个场景, 如果我在代码中引入了第三方控件库,它重写了系统默认控件的样式, 这个时候我们又有自己的样式, 如
// 第三方库
<Style Selector="Button">
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="MinWidth" Value="100" />
</Style>
// 我们自己的
<Style Selector="Button">
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Bottom" />
<Setter Property="Width" Value="50" />
</Style>
引用自官网: 如果你想要修改控件的特定实例的样式
Styles,唯一的选项是应用一个新的Styles为控件实例,并希望它能够重写原始的Styles中的设置过的所有属性.
以上的场景 Button 的宽度是多少? 答 100. 这个对于来自WPF的小朋友就感觉就难受了, 第三方库加了个MinWidth,我又没继承,难道我还要在自己的样式中自己给MinWidth或者重新整个样式吗? 也就是Avalonia UI官方说的一旦一个Style被应用到一个控件上,没有办法移除它。
坑就来了啊,如果第三方库更新了Styles加了个属性咋办? 我也要跟着加?
使用 ControlTheme
所以 V11 版本后引入了 ControlTheme 对于 特定 Control的ControlTheme之间是彼此独立的。
<ControlTheme x:Key="A" TargetType="Button">
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="MinWidth" Value="100" />
</ControlTheme>
// 两个Button的ControlTheme相互独立
<ControlTheme x:Key="B" TargetType="Button">
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Bottom" />
<Setter Property="Width" Value="50" />
</ControlTheme>
问: Button的宽度是多少? 答 50. 这不就跟我们大WPF一样了吗? 如果我还要继承第三方库写的样式咋办? 加上 Baseon 属性即可.
最佳实践
- 开发UI框架时最好使用
ControlTheme定义控件Template, 这也是官方推荐的。 - 利用控件可以应用多个
Styles的优点,标准化一些常用样式, 供控件的扩展UI使用 - 利用
Styles应用优先级比ControlTheme高的优点,- 标准业务里边的多颜色主题使用
Styles - 全局控制应用的主题
- 标准业务里边的多颜色主题使用
- 不要写默认的全局Style
<Style Selector="Button">, 否则所有Button都将受到影响, 官方全局样式里边的已经都替换成ControlTheme了, 有兴趣参考下面链接。
总结
Style & ControlTheme 的特性
独立性
ControlTheme 彼此之间是独立的
Style 彼此是相互覆盖的
如:
<ControlTheme x:Key="A" TargetType="Button">
//...
</ControlTheme>
// 两个Button的ControlTheme相互独立
<ControlTheme x:Key="B" TargetType="Button">
//...
</ControlTheme>
<Style Selector="Button"> // Default Style
<Setter Property="HorizontalContentAlignment" Value="Right" />
<Setter Property="VerticalContentAlignment" Value="Bottom" />
</Style>
// 两个Button的Style有关联关系
<Style Selector="Button.NewStyle"> // 对 Default Style 的修改都有可能影响其他Style
<Setter Property="HorizontalContentAlignment" Value="Left" />
// <Setter Property="VerticalAlignment" Value="Bottom" /> // 来此Default Style
</Style>
继承性
ControlTheme 由于ControlTheme之间相互独立,但是其支持 BaseOn 类似 WPF 的<Style BaseOn="{StaticResource BaseStyle}"
Style 参考上一点独立性, 新增的Style都将继承Default Style
如:
<ControlTheme x:Key="A" TargetType="Button">
//...
</ControlTheme>
// 两个Button的ControlTheme相互独立
<ControlTheme x:Key="B" TargetType="Button" BaseOn="{StaticResource A}">
//...
</ControlTheme>
而 Styles 类似 CSS, 它将所有作用域范围内的Styles的Setters都放在一起应用到控件上. 这也就是为什么原始的Style如果新的Style不需要也要设置相同属性进行覆盖
优先级
从应用样式的角度 Style > ControlTheme 即 Default Style(或者设置了Classes的控件) 的 Setter 都将覆盖 ControlTheme 的 Setter
从定义控件的角度 ControlTheme > Style 即 定义一类新Template(类似WPF的 ControlTemplate) 优先使用ControlTheme, 并且利用 Style 控制上层颜色方案
样式来源
ControlTheme 将遍历 可视树 (Visual Tree), 这种方式也与WPF类似
Style 类似于将所有作用域范围内的所有 Setter 合并并收集起来, 应用到控件实例上.
多Styles 单ControlTheme
控件实例可以引用多个Styles, 引用方式为 Classes="H1 Blue"
控件实例只可以引用一个ControlTheme, 引用方式为 Theme="{StaticResources XXXXTheme}"
参考文档
===

知识共享许可协议 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 0xJins(包含此链接),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 。
Avalonia UI 中 Styles 与 ControlTheme 的区别的更多相关文章
- material UI中withStyles和makeStyles的区别
在material UI中,withStyles和makeStyles是经常使用的两个用于封装样式的函数.对于刚使用material UI的开发者而言,可能不太清楚这两者的区别. 本文简要探究 ...
- 树莓派 Raspberry Pi 4,.net core 3.0 ,Avalonia UI 开发
虽说.net core3.0已经可以用于开发wpf和winform程序,可是遗憾的时目前这core下的wpf还是只能运行在windows下,想要在linux下运行wpf估计还要等一段时间. Avalo ...
- jsp中两种include的区别【转】
引用文章:http://www.ibm.com/developerworks/cn/java/j-jsp04293/ http://www.cnblogs.com/lazycoding/archive ...
- (转)asp.net中Literal与label的区别
asp.net中Literal与label的区别 一.Literal Web 服务器控件概述(摘于MSDN) 可以使用 Literal Web 服务器控件作为页面上其他内容的容器.Literal 最常 ...
- html中submit和button的区别(总结) [ 转自欣步同学 ]
html中submit和button的区别(总结) submit是button的一个特例,也是button的一种,它把提交这个动作自动集成了. 如果表单在点击提交按钮后需要用JS进行处理(包括输入验证 ...
- Android中style和theme的区别
在学习Xamarin android的过程中,最先开始学习的还是熟练掌握android的六大布局-LinearLayout .RelativeLayout.TableLayout.FrameLayou ...
- 【分析】浅谈C#中Control的Invoke与BeginInvoke在主副线程中的执行顺序和区别(SamWang)
[分析]浅谈C#中Control的Invoke与BeginInvoke在主副线程中的执行顺序和区别(SamWang) 今天无意中看到有关Invoke和BeginInvoke的一些资料,不太清楚它们之间 ...
- .NET 跨平台框架Avalonia UI: 填坑指北(二):在Linux上跑起来了
上一章回顾: .NET 跨平台框架Avalonia UI: 填坑指北(一):熟悉UI操作 本篇将要阐述 包括但不仅限于Avalonia及所有Windows到Linux跨平台开发 的一些注意事项: 一 ...
- .NET跨平台框架选择之一 - Avalonia UI
本文阅读目录 1. Avalonia UI简介 Avalonia UI文档教程:https://docs.avaloniaui.net/docs/getting-started 随着跨平台越来越流行, ...
- 【转】为什么我们都理解错了HTTP中GET与POST的区别
GET和POST是HTTP请求的两种基本方法,要说它们的区别,接触过WEB开发的人都能说出一二. 最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数. 你可能自己 ...
随机推荐
- windows服务器使用 azure devops 批量自动发布网站到IIS
最近由于一个API项目,需要利用负载均衡来做支撑,因此需要将同一份代码分发到多个服务器,之前一直手工干这个活,感觉太累了,去开发交流群,还有搜索了一下资料,发现很多人推荐我用ftp.还有磁盘共享等这种 ...
- 深度学习环境安装-conda-torch-Jupyter Notebook
conda的安装 为什么要安装这个,它是什么? 它是一个管理环境的,当我们跑项目的时候,往往这些项目所需要的pickets库和环境是不同的,这时候如果自己的电脑里面只有一个版本的库的话,就运行不了,比 ...
- 原生JavaScript实现一个简单的Promise构造函数示例
下面demo示例,只支持实例的then和catch,代码如下: function PromiseDiffer(fn){ var self = this; this.status = 'pendding ...
- Java读取寄存器数据的方法
在Java中直接读取硬件寄存器(如CPU寄存器.I/O端口等)通常不是一个直接的任务,因为Java设计之初就是为了跨平台的安全性和易用性,它并不直接提供访问底层硬件的API.不过,在嵌入式系统.工业控 ...
- IT男如何走上的自由职业之路。
前言 在博客园的一篇文章<40岁大龄失业程序猿,未来该何去何从>,在下面留言,目前自己在做自由职业,很多人加好友咨询自由职业的事情,对IT行业自由职业比较感兴趣,问怎么能走上这条路,所以才 ...
- HeaderFile (1.2-1.6) 中 hct.h 使用教程
下载 HeaderFile 1.2 HCT 是干什么的 辅助数据生成 主干框架 你需要包含必须的头文件 hct.h 此外,你需要实现如下函数: void create() 数据生成函数 void so ...
- 10款好用的开源 HarmonyOS 工具库
大家好,我是 V 哥,今天给大家分享10款好用的 HarmonyOS的工具库,在开发鸿蒙应用时可以用下,好用的工具可以简化代码,让你写出优雅的应用来.废话不多说,马上开整. 1. efTool efT ...
- Android10.0系统启动之Launcher(桌面)启动流程-[Android取经之路]
Launcher的启动经过了三个阶段: 第一个阶段:SystemServer完成启动Launcher Activity的调用 第二个阶段:Zygote()进行Launcher进程的Fork操作 第三个 ...
- 1.1 HELLO 窗口
跟着教程,开始第一步创建窗口吧!这一节不涉及太多知识. 本节会出现一些名词,我们现在只需要知道它们大概是干什么的就行. ● GLFW:一个专门针对OpenGL的C语言库,通过它提供的接口,我们就可以渲 ...
- CF753B题解
这应该算是一个很脍炙人口的小游戏了吧 (没玩过算我没说) 因为一共有 \(50\) 次询问机会,那最简单直接的方法就不难想到. 我们把 \(0 \sim9\) 全部询问一遍,如果回答两个整数不全为 \ ...