我们来观察一下ControlTemplate控件模块的定义
public class ControlTemplate : FrameworkTemplate
{
public ControlTemplate();
public ControlTemplate(Type targetType);
public Type TargetType { get; set; }
public TriggerCollection Triggers { get; }
protected override void ValidateTemplatedParent(FrameworkElement templatedParent);
}
可以看到在ControlTemplate中定义了一个Triggers 集合,说明可以定义一些触发器,以实现控件的交互效果。我们之前在《样式》章节中学过几种触发器,在这里用例子演示一下ControlTemplate的触发器的用法。
我们将上一章节的例子进行一些微调,因为在使用触发器时,有些细节需要注意。
一、在控件中的ControlTemplate的触发器
<Button Content="将ControlTemplate定义在在控件中"
Width="280"
Height="40"
Margin="10"
Foreground="#747787">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border x:Name="border"
Background="Transparent"
CornerRadius="5"
BorderThickness="1"
BorderBrush="#C9CCD5">
<ContentPresenter x:Name="contentPresenter"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Content" Value="MouseOver" TargetName="contentPresenter"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Content" Value="将ControlTemplate定义在在控件中" TargetName="contentPresenter"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
在上面的例子中,我们在Triggers集合中增加了两个Trigger 对象,条件是当鼠标移上去或鼠标移开的时候,更改了Button的Content属性。
二、在Resources定义的ControlTemplate的触发器
<Window.Resources>
<ControlTemplate x:Key="ButtonTemplate" TargetType="Button">
<Border Background="#C6D2FC"
CornerRadius="5"
BorderThickness="1"
BorderBrush="#545BAD">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Width" Value="300"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Width" Value="280"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Resources>
<Button Content="将ControlTemplate定义在资源中"
Template="{StaticResource ButtonTemplate}"
Height="40" Margin="10" Foreground="#707CA5"/>
上面演示了定义在资源中的控件模板的触发器,需要注意的一点是,我们在触发器执行时更改了Button的宽度,这个时候,要把Button原先设置的Width删除,因为”就近原则“,直接设置控件的属性值大于天,而在模板中设置控件的属性值的权重要小一些。
三、Style样式中的ConControlTemplate的触发器
<Button Content="将ControlTemplate定义在Style样式中"
Width="280" Height="40" Margin="10" >
<Button.Style>
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="border"
CornerRadius="5"
BorderThickness="1"
BorderBrush="#7AAB7D">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="☻"
VerticalAlignment="Center"
Margin="3" FontSize="18"/>
<ContentPresenter Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="#7AAB7D"/>
<Setter Property="Background" Value="White" TargetName="border"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="#7AAB7D" TargetName="border"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
ControlTemplate中使用触发器,还有一个好处是:可以指定设置某个可视化树中的控件对象。比如上面这段代码,当鼠标移上去的时候,我们修改了border对象的背景色,这个背景色其实并不是Button本身的背景颜色,而是Button内部可视化树中的Border的背景颜色。只需要利用Setter的TargetName属性来指定就行了。
而鼠标移上去的时候,我们还修改了Foreground前景颜色,这个Foreground才是Button本身的属性。说明什么问题?说明ControlTemplate中的触发器不但可以修改控件的属性,还可以修改控件模板中的可视化树的元素的属性,它真是太好用了。
我们来看一下运行结果。
要充分了解ControlTemplate控件模板的定义和触发器的使用,还离不开TemplateBinding(模板绑定),它将控件的属性和控件的可视化树元素的属性建立绑定关系,在设计控件模板时,可以更好的设计出控件的结构、外观和交互效果。
当前课程源码下载:(注明:本站所有源代码请按标题搜索)
文件名:064-《ControlTemplate的触发器》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff
——重庆教主 2023年9月28日
当学会了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日
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日
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日
触发器是指当满足预设的条件时去执行一些事务的工具,比如我们希望鼠标移到某个按钮上方时,这个按钮的颜色、大小发生一些改变。这个时候,条件是鼠标移到按钮上,执行的事务是改变按钮的颜色和大小。
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日