什么是样式?样式有什么作用?首先,WPF框架提供了许许多多的控件,而这些控件拥有不同的属性,例如一个button控件的长宽、背景颜色、字体字号、内外边距、边框等,我们可以设置这些属性的值,从而让控件呈现出不同的显示效果。如果有多个button,我们该怎么办呢,每个按钮都去设置一遍属性?显示这是不科学的。于是,我们可以将一系列的属性的设置“集中”起来,将它们定义成一个样式,最后将这个样式再设置到控件上,从而达到“一处定义多处引用”的偷懒行为。
样式——就是一种将一组属性值应用到多个元素的便捷方法。
一、样式的定义
public class Style : DispatcherObject, INameScope, IAddChild, ISealable, IHaveResources, IQueryAmbient
{
public Style();
public Style(Type targetType);
public Style(Type targetType, Style basedOn);
public bool IsSealed { get; }
public Type TargetType { get; set; }
public Style BasedOn { get; set; }
public TriggerCollection Triggers { get; }
public SetterBaseCollection Setters { get; }
public ResourceDictionary Resources { get; set; }
public override int GetHashCode();
public void RegisterName(string name, object scopedElement);
public void Seal();
public void UnregisterName(string name);
}
样式的类型叫Style,它继承于DispatcherObject,它最重要的几个属性如下:
TargetType属性:这是一个类类型,也就是一个反射,这个属性指明了当前样式要作用于哪种类型的控件上。因为WPF中有许多的控件,我们定义一个样式时,必须要指明这个样式的“适用范围”。
BasedOn属性:样式也有继承的概念,所以,BasedOn指明了当前样式继承于哪个样式
Triggers属性:这是一个集合属性,表示触发器的定义,当满足某些条件时,触发哪些行为,以使控件达到一定的“节目效果”。比如当鼠标移上去时,控件的背景颜色变成红色。这些的效果就可以通过定义控件的触发器来设置。
Setters属性:这也是一个集合属性,样式是控件属性的值的“提前设置”,所以,我们对控件属性的值的设置都是以Setter条目的形式,一条一条的放到这个Setters集合中。
Resources属性:这个属性叫资源字典。在正式讲解样式之前,我们要先介绍一下资源字典的概念及其用途。它表示一些资源,以字典的形式进行维护,方便程序引用。下一节,我们先介绍ResourceDictionary。
二、Style样式如何使用
当我们定义好一个Style之后,如此去使用它?首先,我们在《FrameworkElement基类》那一节中也曾了解过Style的概念,并且我们会发现FrameworkElement基类就有一个Style属性。而所有的控件都继承于FrameworkElement基类,所以,我们只需要将定义好的样式赋值到控件的Style属性即可。
2.1 在Application.Resources中定义样式
<Application x:Class="HelloWorld.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:HelloWorld"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style x:Key="ButtonStyle" TargetType="Button">
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="30"/>
<Setter Property="Background" Value="Red"/>
<Setter Property="Foreground" Value="White"/>
</Style>
</Application.Resources>
</Application>
2.2 在XAML中引用样式
<Grid>
<Button Content="文字块" Style="{StaticResource ButtonStyle}"/>
</Grid>
注意:在引用样式时,我们有两种方式,分别是DynamicResource和StaticResource,后面再写上样式的名称。DynamicResource表示动态资源,StaticResource表示静态资源。这两者的区别是:静态资源在第一次编译后即确定其对象或值,之后不能对其进行修改。动态资源则是在运行时决定,当运行过程中真正需要时,才到资源目标中查找其值。因此,我们可以动态地修改它。由于动态资源的运行时才能确定其值,因此效率比静态资源要低。
另外,我们在定义样式的条目时,实际上是实例化了一个Setter对象。它有两个关键是属性,分别是Property和Value。Property表示要设置的属性名,Value表示要设置的属性值。有点像键值对的感觉。
public class Setter : SetterBase, ISupportInitialize
{
public Setter();
public Setter(DependencyProperty property, object value);
public Setter(DependencyProperty property, object value, string targetName);
public DependencyProperty Property { get; set; }
public object Value { get; set; }
public string TargetName { get; set; }
public static void ReceiveMarkupExtension(object targetObject, XamlSetMarkupExtensionEventArgs eventArgs);
public static void ReceiveTypeConverter(object targetObject, XamlSetTypeConverterEventArgs eventArgs);
}
另外,Setter从定义上看,它还有一个属性叫TargetName,顾名思义,目标名称,也就是这一对属性名和值是哪个控件的属性名和值。通常它在定义触发器时使用,我们将在后面的场景中去学习它。
这一节,我们只是简单的介绍了样式的来龙去脉,待我们了解了资源字典之后,会进一步的学习样式。
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:047-《WPF样式概述》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年9月11日
WPF中的资源是指可以在应用中的不同位置重复使用的对象。而拥有这些对象的文件,我们可称为资源文件。这些资源文件可以编译到程序集中,可使用包 URI 来引用一组特殊的 WPF 应用程序代码文件,包括窗口、页面、流文档和资源字典。 例如,可以将 Application.StartupUri 属性设置为包 URI,用于引用要在应用程序启动时加载的窗口或页面。
<Application x:Class="HelloWorld.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:HelloWorld"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
在App.xaml文件中,通常默认的StartupUri属性值为MainWindow.xaml,这个MainWindow.xaml文件实际上就是一个资源文件,它包含了主窗体界面的所有XAML代码。
一、使用资源文件
我们可以在XAML中删除StartupUri属性的设置,在Application的后端C#代码中去引用主窗体的资源文件。
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Uri uri = new Uri("MainWindow.xaml", UriKind.Relative);
base.StartupUri = uri;
}
}
如上所示,我们重写了OnStartup方法成员,利用Uri包引入MainWindow.xaml,并设置到StartupUri属性,F5运行,同样会启动主窗体。
WPF的资源的形式是多样化的,它可以是一个主窗体,也可以是一个画笔,或一个样式,或一个别的对象。关键的一点是,它是一个对象。什么是对象?一个类型被实例化之后,就成了一个对象。所以,我们从本质上讲,资源就是类型实例化之后的对象。
那么,这些资源在程序运行过程中被放在哪儿了?
二、资源的老家
首先,资源是以字典的形式存在于程序中——也就是ResourceDictionary(资源字典)。其次,它们通常保存在Resources属性中。哪些类型有Resources属性?
答案是:Application类、FrameworkElement基类和FrameworkContentElement基类。
来自官方的引述
每个框架级元素(FrameworkElement 或 FrameworkContentElement)都具有 Resources 属性,该属性是包含已定义资源的 ResourceDictionary 类型。 你可以在任何元素上定义资源,例如 Button。 但是,最常在根元素上定义资源。资源字典中的每个资源都必须具有唯一键。 在标记中定义资源时,可通过 x:Key 指令来分配唯一键。 通常情况下,这个键是一个字符串;但是,也可使用相应的标记扩展将其设置为其他对象类型。 资源的非字符串键用于 WPF 中的某些功能区,尤其是样式、组件资源和数据样式。
从Resources属性可以分析出——每个控件都可以单独定义资源,因为它们都继承了Resources属性。但是,通常情况下,我们会在Application中去定义Resources属性,这样全局或所有的控件都可以引用。
关于如何定义资源,以及了解资源字典的概念与用法,我们将在下一节介绍。
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:048-《Resource资源》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年9月11日
Application类、FrameworkElement基类和FrameworkContentElement基类都有一个叫Resources的属性,其类型就是ResourceDictionary,我们称为资源字典。
一、ResourceDictionary资源字典的定义
public class ResourceDictionary : IDictionary, ICollection, IEnumerable, ISupportInitialize, IUriContext, INameScope
{
public ResourceDictionary();
public object this[object key] { get; set; }
public ICollection Keys { get; }
public DeferrableContent DeferrableContent { get; set; }
public bool InvalidatesImplicitDataTemplateResources { get; set; }
public bool IsReadOnly { get; }
public bool IsFixedSize { get; }
public Uri Source { get; set; }
public Collection<ResourceDictionary> MergedDictionaries { get; }
public ICollection Values { get; }
public int Count { get; }
public void Add(object key, object value);
public void BeginInit();
public void Clear();
public bool Contains(object key);
public void CopyTo(DictionaryEntry[] array, int arrayIndex);
public void EndInit();
public object FindName(string name);
public IDictionaryEnumerator GetEnumerator();
public void RegisterName(string name, object scopedElement);
public void Remove(object key);
public void UnregisterName(string name);
protected virtual void OnGettingValue(object key, ref object value, out bool canCache);
}
从ResourceDictionary的定义上看,它内部拥有两个集合,分别是Keys和Values,并且它还拥有一个迭代器,可以根据key名称快速地访问某个Values集合中的元素;最后就是这个迭代器的返回值是object类型,说明一个问题:资源字典的集合中的元素可以是任意类型的实例。这句话非常重要,我们接下来就演示它的用途。
此外,资源字典还有一个很重要的属性——MergedDictionaries。字面意思可以理解成合并的资源字典集合。也就是说,Applicaton类的Resources属性本身就可以定义许多的资源,而这些资源可以是某个Style样式,也可以是某个画笔,或某个转换器,还可以是ResourceDictionary,但是要把ResourceDictionary放到MergedDictionaries集合中。
最后一个比较重要的属性是Source。它表示当前资源字典的数据源——也就是要加载资源的 统一资源标识符 (URI)。
接下来,我们以四种方式定义Style,并演示ResourceDictionary的一些用法。
二、资源字典与样式的用法
2.1创建一个资源字典文件
在项目中新建一个Style文件夹,右键-添加-资源字典文件。创建一个Button.xaml的资源文件,并在其中写下内容。
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="BlueButtonStyle" TargetType="Button">
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="30"/>
<Setter Property="Background" Value="Blue"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Margin" Value="3"/>
</Style>
</ResourceDictionary>
注意,资源文件都是以ResourceDictionary实例开头的对象,然后我们在其中编写了一个Style样式。
回到项目的App.xaml文件中,编写如下内容
<Application x:Class="HelloWorld.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:HelloWorld"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<SolidColorBrush x:Key="ButtonBackground" Color="Red"/>
<SolidColorBrush x:Key="ButtonForeground" Color="White"/>
<Style x:Key="ButtonStyle" TargetType="Button">
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="30"/>
<Setter Property="Background" Value="{StaticResource ButtonBackground}"/>
<Setter Property="Foreground" Value="{StaticResource ButtonForeground}"/>
<Setter Property="Margin" Value="3"/>
</Style>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Style/Button.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
我们在Application的Resources属性中实例化了一个ResourceDictionary对象,并在其中定义了两个SolidColorBrush对象,一个style样式,以及在MergedDictionaries集合中添加了一个ResourceDictionary对象,其数据源指向了Button.xaml资源文件。
最后,我们来到主窗体的前端代码:
<Window x:Class="HelloWorld.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWorld"
xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
mc:Ignorable="d" FontSize="14"
Title="WPF中文网之控件课程 - www.wpfsoft.com" Height="350" Width="500">
<Window.Resources>
<Style x:Key="GreenButtonStyle" TargetType="Button">
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="30"/>
<Setter Property="Background" Value="Green"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Margin" Value="3"/>
</Style>
</Window.Resources>
<StackPanel VerticalAlignment="Center">
<Button Content="红色按钮" Style="{StaticResource ButtonStyle}"/>
<Button Content="蓝色按钮" Style="{StaticResource BlueButtonStyle}"/>
<Button Content="绿色按钮" Style="{StaticResource GreenButtonStyle}"/>
<Button Content="橙色按钮">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="30"/>
<Setter Property="Background" Value="Orange"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Margin" Value="3"/>
</Style>
</Button.Style>
</Button>
</StackPanel>
</Window>
在上面的代码中,我们在Window的Resources定义了一个样式,同时在Button中也定义了一个样式,如此,我们就演示了4种定义style的方法。
最后来看一下最终的呈现效果
总结:Resources属性的值只能是一个ResourceDictionary对象,一个ResourceDictionary对象中可以定义多个资源。如果有多个ResourceDictionary对象,则必须使用MergedDictionaries属性。任意类型都可以在Resources中被实例化,但是必须在实例化时指明一个key,因为在xaml中要引入定义好的资源,都是以key进行查找的。
上面的示例中,我们演示了style样式的Setters集合,接下来,我们来演示一下style样式的Triggers集合。
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:049-《ResourceDictionary资源字典》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年9月11日
触发器是指当满足预设的条件时去执行一些事务的工具,比如我们希望鼠标移到某个按钮上方时,这个按钮的颜色、大小发生一些改变。这个时候,条件是鼠标移到按钮上,执行的事务是改变按钮的颜色和大小。
WPF提供了5种触发器,以满足不同场合下的使用要求。触发器主要运用的场景在Style、ControlTemplate、DataTemplate三个地方。我们先介绍Style样式中的用法,待学习模板知识时,再进一步学习触发器在模板中的使用。
触发器名称 | 说明 |
Trigger | 监测依赖属性的变化、触发器生效 |
MultiTrigger | 通过多个条件的设置、达到满足条件、触发器生效 |
DataTrigger | 通过数据的变化、触发器生效 |
MultiDataTrigger | 多个数据条件的触发器 |
EventTrigger | 事件触发器, 触发了某类事件时, 触发器生效。 |
一、Trigger触发器的定义
public class Trigger : TriggerBase, IAddChild, ISupportInitialize
{
public Trigger();
public DependencyProperty Property { get; set; }
public object Value { get; set; }
public string SourceName { get; set; }
public SetterBaseCollection Setters { get; }
public static void ReceiveTypeConverter(object targetObject, XamlSetTypeConverterEventArgs eventArgs);
}
从定义上看,它有4个属性,我们一一分析
Property属性:表示定义触发器所指向的属性名称,需要注意的是,它的类似是DependencyProperty(依赖属性),也就是说,触发器所生效的属性必须是WPF中的依赖属性。
Value属性:表示定义触发器所指向的属性的值,这两个属性要连起来理解,即某个属性的值等于预设的值时,此时将该触发器将被触发,至于要执行哪些具体的事务,就要看Setters集合中定义了哪些项。
SourceName属性:获取或设置与导致关联的 setter 要应用的属性对象的名称。
Setters属性:这是一个集合,类似于Style样式的Setters,且用途是一致的,就是指当前触发器被触发时,将执行Setters里面的内容项。
二、Trigger示例
前端代码
<Window x:Class="HelloWorld.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWorld"
xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
mc:Ignorable="d" FontSize="14"
Title="WPF中文网之控件课程 - www.wpfsoft.com" Height="350" Width="500">
<Window.Resources>
<Style x:Key="GreenButtonStyle" TargetType="Button">
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="30"/>
<Setter Property="Background" Value="Green"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Margin" Value="3"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="Width" Value="150"/>
<Setter Property="Height" Value="50"/>
<Setter Property="Content" Value="鼠标移入"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel VerticalAlignment="Center">
<Button Content="绿色按钮" Style="{StaticResource GreenButtonStyle}"/>
<CheckBox Content="CheckBox">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="30"/>
<Setter Property="Background" Value="Orange"/>
<Setter Property="Foreground" Value="Green"/>
<Setter Property="Margin" Value="3"/>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Foreground" Value="Red"/>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Foreground" Value="Orange"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="FontWeight" Value="Normal"/>
</Trigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
</StackPanel>
</Window>
在按钮的样式中,我们定义了一个触发器,条件是当按钮的IsMouseOver属性等于True时,执行的事务是将按钮的前景色改成红色,同时改变按钮的尺寸。
在CheckBox复选项的样式中,我们定义的触发器条件是当CheckBox的IsChecked属性等于True时,执行的事务是将复选框的前景色改成红色。
需要注意的是:Trigger触发器的条件应该是当前控件拥有的属性名称。比如Button按钮没有IsChecked属性,就不可设置与CheckBox相同的触发器。
大多数控件都有IsMouseOver属性,包括CheckBox,所以,我们在鼠标移到CheckBox上方时,将其字体变成了粗体。另外,完整的触发器写法应如CheckBox一样,如果是bool型的属性,Value的值就有两个,分别是True和False,所以,条件也就有了两个,如果只写了True的情况,WPF也会默认一个False条件的触发器。
下一节,我将介绍多条件的触发器。
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:050-《Trigger触发器》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年9月11日
MultiTrigger表示多个条件同时满足时才会触发的触发器。
public sealed class MultiTrigger : TriggerBase, IAddChild
{
public MultiTrigger();
public ConditionCollection Conditions { get; }
public SetterBaseCollection Setters { get; }
}
一、属性成员
1.1 Conditions属性
MultiTrigger的Conditions属性是一个集合,表示条件。这个集合的元素是Condition类型。
public sealed class Condition : ISupportInitialize
{
public Condition();
public Condition(DependencyProperty conditionProperty, object conditionValue);
public Condition(BindingBase binding, object conditionValue);
public Condition(DependencyProperty conditionProperty, object conditionValue, string sourceName);
public DependencyProperty Property { get; set; }
public BindingBase Binding { get; set; }
public object Value { get; set; }
public string SourceName { get; set; }
public static void ReceiveMarkupExtension(object targetObject, XamlSetMarkupExtensionEventArgs eventArgs);
public static void ReceiveTypeConverter(object targetObject, XamlSetTypeConverterEventArgs eventArgs);
}
通常情况下,我们只需要使用Property属性和Value属性即可,即“某个属性达到某个值时”这样一种条件定义。
<Condition Property="IsMouseOver" Value="True"/>
1.2 Setters属性
MultiTrigger的Setters属性也是一个集合,表示触发器触发后要设置的项。比如:
<Setter Property="Foreground" Value="Red"/>
二、MultiTrigger示例
<CheckBox x:Name="checkbox">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Content" Value="MultiTrigger"/>
<Setter Property="Width" Value="150"/>
<Setter Property="Height" Value="30"/>
<Setter Property="Background" Value="Orange"/>
<Setter Property="Foreground" Value="Green"/>
<Setter Property="Margin" Value="3"/>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
<Condition Property="IsChecked" Value="True"/>
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter Property="Foreground" Value="Red"/>
<Setter Property="Content" Value="多条件触发器"/>
</MultiTrigger.Setters>
</MultiTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
在上面的例子中,我们通过Style样式设置了CheckBox的Content及其它属性。然后在样式中实例化了一个MultiTrigger多条件触发器,并为其Conditions集合增加了两个条件,分别是IsMouseOver等于True和IsChecked等于True,当条件满足时,会改变CheckBox的前景色为红色,同时,Content变成"多条件触发器"。
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:051-《MultiTrigger多条件触发器》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年9月13日
DataTrigger数据触发器,它会在绑定数据满足指定条件时应用属性值或执行操作。
public class DataTrigger : TriggerBase, IAddChild
{
public DataTrigger();
public BindingBase Binding { get; set; }
public object Value { get; set; }
public SetterBaseCollection Setters { get; }
public static void ReceiveMarkupExtension(object targetObject, XamlSetMarkupExtensionEventArgs eventArgs);
}
DataTrigger拥有一个Binding属性,表明它可以绑定某个控件的属性,或者是某个ViewModel的属性,Value属性则是表示绑定的属性达到某个值时,触发条件成立,然后去执行Setters集合里面的内容。
接下来,我们以一个例子来演示DataTrigger绑定ViewModel属性以及DataTrigger绑定控件属性并触发相应的操作。
前端代码
<DataGrid ItemsSource="{Binding Persons}" SelectedItem="{Binding Person}" AutoGenerateColumns="False">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding Age}" Value="19">
<Setter Property="Background" Value="LightBlue"/>
</DataTrigger>
<DataTrigger Binding="{Binding Age}" Value="20">
<Setter Property="Background" Value="LightGreen"/>
</DataTrigger>
<DataTrigger Binding="{Binding Age}" Value="21">
<Setter Property="Background" Value="LightCoral"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=_CheckBox,Path=IsChecked}" Value="True">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="姓名" Binding="{Binding Name}"/>
<DataGridTextColumn Header="年龄" Binding="{Binding Age}"/>
<DataGridTextColumn Header="生日" Binding="{Binding Address}"/>
</DataGrid.Columns>
<!--<ListView.View>
<GridView>
<GridViewColumn Header="姓名" DisplayMemberBinding="{Binding Name}" Width="60"/>
<GridViewColumn Header="年龄" DisplayMemberBinding="{Binding Age}" Width="auto"/>
<GridViewColumn Header="地址" DisplayMemberBinding="{Binding Address}" Width="auto"/>
</GridView>
</ListView.View>-->
</DataGrid>
我们将前面的例子稍做修改,采用DataGrid控件绑定Persons集合,在DataGridRow的Style样式中,实例化了4个DataTrigger,前端3个DataTrigger的条件是:当Person.Age等于19、20、21时,将当前行的背景颜色分别改成LightBlue、LightGreen和LightCoral。
注意最后一个DataTrigger,它绑定了CheckBox的IsChecked属性,当IsChecked=True时,将当前行的字体属性进行了一些设置。
最后,我们来生成一些Penson元素,看看前端的呈现效果。
当CheckBox被选中后,即IsChecked=True,此时会将每一行的字体的属性都进行改动。
完整的代码请在下方下载。
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:058-《DataTrigger数据触发器》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年9月18日
当学会了DataTrigger数据触发器和MultiTrigger多条件触发器,MultiDataTrigger就比较好理解了,它就是前面两个触发器的结合体。
public sealed class MultiDataTrigger : TriggerBase, IAddChild
{
public MultiDataTrigger();
public ConditionCollection Conditions { get; }
public SetterBaseCollection Setters { get; }
}
从定义上看,它与MultiTrigger多条件触发器一模一样,只是内部的实现略有不同。我们可以将一节的例子稍作修改,来演示一下MultiDataTrigger的用法。
<DataGrid ItemsSource="{Binding Persons}" SelectedItem="{Binding Person}" AutoGenerateColumns="False">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding Age}" Value="19">
<Setter Property="Background" Value="LightBlue"/>
</DataTrigger>
<DataTrigger Binding="{Binding Age}" Value="20">
<Setter Property="Background" Value="LightGreen"/>
</DataTrigger>
<DataTrigger Binding="{Binding Age}" Value="21">
<Setter Property="Background" Value="LightCoral"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=_CheckBox,Path=IsChecked}" Value="True">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=Age}" Value="20"/>
<Condition Binding="{Binding Path=Name}" Value="张三"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Foreground" Value="Red"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="FontWeight" Value="Bold"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="姓名" Binding="{Binding Name}"/>
<DataGridTextColumn Header="年龄" Binding="{Binding Age}"/>
<DataGridTextColumn Header="生日" Binding="{Binding Address}"/>
</DataGrid.Columns>
<!--<ListView.View>
<GridView>
<GridViewColumn Header="姓名" DisplayMemberBinding="{Binding Name}" Width="60"/>
<GridViewColumn Header="年龄" DisplayMemberBinding="{Binding Age}" Width="auto"/>
<GridViewColumn Header="地址" DisplayMemberBinding="{Binding Address}" Width="auto"/>
</GridView>
</ListView.View>-->
</DataGrid>
在上面的前端代码中,我们增加了一个MultiDataTrigger触发器的实例。
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=Age}" Value="20"/>
<Condition Binding="{Binding Path=Name}" Value="张三"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Foreground" Value="Red"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="FontWeight" Value="Bold"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
条件是,当Person是一个20岁的“张三”时,把当前行的字体进行了一些特别设置。
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:059-《MultiDataTrigger数据触发器》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年9月18日
EventTrigger,表示某个事件发生时,执行某一组操作,而这一组操作,通常是对当前控件或其它控件的属性做一些改变。我们先来看看它的定义。
一、EventTrigger的定义
[ContentProperty("Actions")]
public class EventTrigger : TriggerBase, IAddChild
{
public EventTrigger();
public EventTrigger(RoutedEvent routedEvent);
public RoutedEvent RoutedEvent { get; set; }
public string SourceName { get; set; }
public TriggerActionCollection Actions { get; }
public bool ShouldSerializeActions();
protected virtual void AddChild(object value);
protected virtual void AddText(string text);
}
RoutedEvent :表示一个事件,用来激活当前触发器。
SourceName:表示一个控件的名称,即是哪个控件的事件发生后,去激活事件触发器。
Actions :获取事件发生时要应用的操作的集合。这个集合的元素只能是BeginStoryboard,表示开始一个故事板,故事板里面将会执行一个动画。
关于动画,我们会在后面的章节中详细讲解,本例中,我们将以DoubleAnimation动画和DoubleAnimationUsingKeyFrames关键帧动画去执行一组操作。
二、EventTrigger示例
前端代码
<Window x:Class="HelloWorld.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWorld"
xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
mc:Ignorable="d" FontSize="14"
Title="WPF中文网之数据绑定 - www.wpfsoft.com" Height="350" Width="500">
<Window.Resources>
<Storyboard x:Key="OnChecked">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="_LeftBorder">
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="OnUnchecked">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="_LeftBorder">
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="200"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="ToggleButton.Checked" SourceName="_CheckBox">
<BeginStoryboard Storyboard="{StaticResource OnChecked}"/>
</EventTrigger>
<EventTrigger RoutedEvent="ToggleButton.Unchecked" SourceName="_CheckBox">
<BeginStoryboard Storyboard="{StaticResource OnUnchecked}"/>
</EventTrigger>
</Window.Triggers>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" x:Name="_LeftBorder" Width="188" Background="LightCyan">
<TextBlock Text="菜单区域" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<Border Grid.Column="1" x:Name="_RightBorder" >
<CheckBox x:Name="_CheckBox">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Width" Value="50"/>
<Setter Property="Height" Value="50"/>
<Setter Property="Content" Value="开"/>
<Setter Property="Background" Value="LightGreen"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<Border Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" CornerRadius="60" Background="{TemplateBinding Background}">
<TextBlock Text="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="Red"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Content" Value="关"/>
</Trigger>
<EventTrigger RoutedEvent="MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.300" Storyboard.TargetProperty="Width" To="60" />
<DoubleAnimation Duration="0:0:0.300" Storyboard.TargetProperty="Height" To="60" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.300" Storyboard.TargetProperty="Width" To="50" />
<DoubleAnimation Duration="0:0:0.300" Storyboard.TargetProperty="Height" To="50" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
</Border>
</Grid>
</Window>
我们先来看看DoubleAnimation动画演示。
我们为CheckBox控件编写了一个样式,在样式的Triggers集合中,实例化了两个EventTrigger ,对应的事件分别是CheckBox控件MouseEnter和MouseLeave事件,在各自的触发器中又分别实例化了两个DoubleAnimation对象,当鼠标进入时,改变CheckBox的宽度和高度为60,当鼠标移出时,还原为50。
然后,我们来看看DoubleAnimationUsingKeyFrames动画演示。
首先我们在Window.Resources中定义了两个故事板,分别改变_LeftBorder控件的宽度,什么时候执行这两个故事板?这个时候,我们在Window.Triggers中实例化了两个EventTrigger,条件是当_CheckBox的Checked事件触发时,将_LeftBorder控件的宽度改为0,当_CheckBox的UnChecked事件触发器,将_LeftBorder控件的宽度改为188,由于是关键帧动画,所以,我们会看到左侧的菜单区域被缓缓关闭和打开。
利用EventTrigger和WPF动画,我们就可以在XAML前端实现很多事件操作特效,让UI的交互更加友好。
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:060-《EventTrigger事件触发器》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年9月19日