在使用WPF编写客户端代码时,我们会在VM下解耦业务逻辑,而剩下与功能无关的内容比如动画、视觉效果,布局切换等等在数量和复杂性上都超过了业务代码。而如何更好的简化这些编码,WPF设计人员使用了Style和Behavior来帮助我们构建一致性、组织性好的代码。
这一章的目的是理解我们使用行为和资源的目标。使用这2个内容使我们创建封装一些通用用户界面功能的行为。比如启动故事板,加入重力的动画效果,我们要把思维给打开,我们做的东西是为了通用,而不是为了业务,因为业务在这个时刻只存在于VM中。(即使个人能力所限,或者实际情况所限,V下面还是有业务代码。但是我们心中要有这个自信,我做WPF开发,那么在未来我也能设计出来堪比WPF这种优秀的的框架,如果没有自信和信心,别人一说就受到了打击,那么什么时间才能成为大佬,别说成为大佬了,可能自己慢慢的就放弃了把),跑题了,简单来说就是我们使用行为和样式设计出来可以添加到各种控件的通用效果。这里不想考虑更多的内容,比如自定义控件。
先讲样式和触发器,我们设计窗体只有暗色风格,在此风格下的按钮都是黑底白字。
实际效果如下图:
我们看到如果这里有N个按钮,那么所有的代码上都要写自己属性对应的样式。我们使用资源可以规划一些统一的样式。而统一的样式,就被我们放到了资源里面。我们一点一点改进我们的代码,修改代码如下。
我们看到了我们在Window节点的Resources下添加了一个Style,并且设置了TargetType为Button。在Button元素内,我删除了对应的代码。这个时候我们启动程序。发现程序的效果是一样的。那么这个时候我们在添加其他按钮,就自动使用了这个样式。
如果在使用Style的时候,不指定Key,那么所有加载了资源的元素都会默认使用这个资源。我们给Style指定一个Key,并设置一个Button的Style观察效果,代码如下:
·
我们发现没有样式添加了Key之后,没有缺少Key的TargetType等于Button的资源后,没有引用Style的Button被修改回系统默认的了。而我们使用Style={StaticResource }资源的样式的Button外观就变成了我们资源中定义的。
样式中还有一个关键的点,是样式的继承。从一个样式中继承公共的部分后,可以实现自己特殊部分的样式,比如我们在继承DarkButtonStyle的样式实现一个警告的按钮的样式。假设统一的警告按钮风格是字体会更粗。我们需要添加一个新的样式继承自DarkButtonStyle并FontWeight属性,同时使警告的控件引用该样式,代码如下:
这样我们就实现了样式的继承,但是代码中,为了通用,还是尽量减少样式的继承,因为要改动代码的话,涉及的一旦包含继承关系,在修改外观时就需要考虑改动样式资源带来的影响,但是会让长期稳定迭代的代码更加结构化。一般都是一个控件的几种形态,建议用样式的继承。
我们在控件引用资源后,我们发现虽然外观修改了,但是鼠标经过,等其他事件时,控件依然没有对应我们要的风格。为了简化对应的事件代码,WPF提出了触发器的概念,在这里我们可以使用触发器来方便的维护控件的外观。
我们在前面代码的基础上添加触发器,如果按钮被禁用,则修改前景色为红色:
using System.Windows;
namespace StyleAndBehavior
{
///
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void SetButtonADisableButton\_OnClick(object sender, RoutedEventArgs e)
{
AButton.IsEnabled = false;
}
}
}
从这个代码中,我们看到了当我们点击按钮B时,按钮A的被设置了Disable无法使用,同时前景色被改成了白色(背景色的变化我们目前先不关注。后面会讲样式的重写,这里只关注我们前景色的变化)。
我们在资源上尝试添加其他触发器,完整代码如下,就会发现触发器可以帮助我们通过监听属性的变化直接修改样式。我们的Button获取焦点,和单击按下后,前景色都会发生变化。
还有一种是满足多个属性同时变更要求的触发器,MultiTriggers。使用这个可以监听多个属性的变化满足条件时设置对应触发器绑定的属性。
我们使用了MultiTrigger来实现多属性变化的触发器,用来设置对应场景下的UI变化。我们这里设置了前景色为橙色。
因为还没有讲到MVVM所以还有一个DataTrigger这里就先不讲了。后面写自定义控件时通过MVVM会讲到这个DataTrigger的使用。原理是一样的。只是使用DataTrigger绑定时监听的时VM对象下的属性。
接下来是事件触发器。事件触发器需要传入一个故事板对象,我们可以使用事件触发器来实现一个鼠标移入时字体慢慢变大, 鼠标移出时字体慢慢变小的动画效果。
代码已经实现了,但是因为最近搬家写代码用的电脑不一样,这个电脑没有录屏软件,所以实际效果没法录屏,复制代码跑起来看看啦。