模板(Template): WPF系统不但支持传统的Winfrom编程的用户界面和用户体验设计,更支持使用专门的设计工具Blend进行专业设计,同时还推出了以模板为核心的新一代设计理念。 在WPF中,通过引入模板(Template)微软将数据和算法的“内容”与“形式”解耦了。模板是算法和数据的外衣,决定了它们长什么样子。
WPF中的模板(Template)分为两大类:
- ControlTemplate是算法内容的表现形式,一个控件怎样组织其内部结构才能更符合业务逻辑和需求。
- DataTemplate是数据内容表现形式,决定一条数据显示成什么样子。
Style(样式):设置控件样式,构成Style重要的两个元素是Setter和Trigger,Setter类帮助我们设置控件的静态外观风格,Trigger类则帮助我们设置控件的行为风格。
Template与Style联系和区别:如果只需对控件进行小幅度修饰(调整大小、位置、字体、颜色等)就用style,如果需要改变控件的外观和行为就用controlTemplate(形状、事件触发如鼠标停留效果等)。在实际项目中,经常把Template定义在Style中,通过Style 中的Property来设置控件的Template属性。
实例链接:https://download.csdn.net/download/lvxingzhe3/87654176
ControlTemplate
控件模板主要有两个重要属性:VisualTree内容属性和Triggers触发器。所谓VisualTree(视觉树),就是呈现我们所画的控件。Triggers可以对我们的视觉树上的元素进行一些变化。一般用于单内容控件。如设置一个圆角Button的ControlTemplate实例如下:
<Window x:Class="WpfTemplate.ControlTemplateDemo"
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:WpfTemplate"
mc:Ignorable="d"
Title="ControlTemplateDemo" Height="450" Width="800">
<Window.Resources>
<ResourceDictionary>
<!--设置控件样式-->
<Style TargetType="Button" x:Key="btnStyle">
<!--Setter设置控件静态属性-->
<Setter Property="FontSize" Value="16"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}" >
<Border x:Name="back" BorderBrush="{TemplateBinding Control.BorderBrush}" Background="LightBlue" CornerRadius="5">
<!--ControlPresenter:内容占位符-->
<ContentPresenter Content="{TemplateBinding ContentControl.Content}" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<!--Triggers设置控件的行为风格-->
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="back" Property="Background" Value="Orange"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Window.Resources>
<Grid>
<!--设置按钮圆角-->
<Button Content="取消" Width="100" Height="30" Style="{StaticResource btnStyle}" />
</Grid>
</Window>
效果如图:
Note:
- Style设置Key值,控件引用其Key来设置自身样式;如果Style没有设置Key值,则Style作用域内所有TargetType类型控件都默认使用其样式。
- ControlPresenter 通常叫做内容占位符,用来替换ContentControl控件。如果没有ControlPresenter ,内容控件就没有内容显示(Button上的字将不显示)。ItemsPresenter用于显示条目数据,作为条目内容占位符。
DataTemplate
允许定制.NET对象的外观,也就是数据的外观,常用在以下3处:ContentControl的ContentTemplate属性,用于定制ContentControl内容的外观;ItemsControl的ItemTemplate属性,用于定制ItmsControl数据条目的外观;GridViewColumn的CellTemplate属性,相当于定制GridViewColumn单元格数据的外观。
1.ContentTemplate使用:
<Window x:Class="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:MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="150" Width="360">
<Window.Resources>
<DataTemplate x:Key="template1">
<TextBlock Text="{Binding}" FontSize="12" FontWeight="Bold" TextWrapping="Wrap"></TextBlock>
</DataTemplate>
</Window.Resources>
<Grid>
<ContentControl Name="contCtrl" ContentTemplate="{StaticResource template1}"
Content="This is the content of the content control."/>
</Grid>
</Window>
2.ItemTemplate使用:
后端代码:
using System;
using System.Collections.Generic;
using System.Windows;
namespace WpfTemplate
{
/// <summary>
/// DataTemplateDemo.xaml 的交互逻辑
/// </summary>
public partial class DataTemplateDemo : Window
{
public List<Book> BookList { get; set; } = new List<Book>();
public DataTemplateDemo()
{
InitializeComponent();
BookList.Add(new Book() { Title = "三国演义", Author = "罗贯中",Time=DateTime.Now.AddYears(-200) });
BookList.Add(new Book() { Title = "红楼梦", Author = "曹雪芹", Time = DateTime.Now.AddYears(-150) });
BookList.Add(new Book() { Title = "西游记", Author = "吴承恩", Time = DateTime.Now.AddYears(-230) });
}
}
}
前端代码:
<Window x:Class="WpfTemplate.DataTemplateDemo"
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:WpfTemplate"
mc:Ignorable="d"
Title="DataTemplateDemo" Name="win" Height="400" Width="600">
<Window.Resources>
<DataTemplate x:Key="MyDataTemplate">
<StackPanel Orientation="Horizontal">
<Border Background="Pink">
<TextBlock Text="{Binding Title}"/>
</Border>
<Button Content="{Binding Author}" Cursor="Hand" Margin="10,0"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox Grid.Row="1" ItemsSource="{Binding BookList,ElementName=win}" ItemTemplate="{StaticResource MyDataTemplate}"/>
</Grid>
</Window>
3.CellTemplate使用
<Window x:Class="WpfTemplate.DataTemplateDemo"
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:WpfTemplate"
mc:Ignorable="d"
Title="DataTemplateDemo" Name="win" Height="400" Width="600">
<Grid>
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding BookList,ElementName=win}" Grid.Row="1" Grid.Column="1">
<DataGrid.Columns>
<DataGridTextColumn Header="书名" Binding="{Binding Title}" />
<DataGridTextColumn Header="作者" Binding="{Binding Author}" />
<DataGridTemplateColumn Header="时间">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding Time}" BorderThickness="0" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
ItemsPanelTemplate使用:
ItemsPanelTemplate可以被设置为ItemsControl的ItemsPanel。例中,ItemsControl的条目显示默认是垂直排列,通过ItemsPanel属性修改为水平排列。
<Grid>
<ListBox>
<!--ItemsPanel-->
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<!--条目-->
<TextBlock Text="Allan"/>
<TextBlock Text="Kevin"/>
<TextBlock Text="Drew"/>
<TextBlock Text="Timothy"/>
</ListBox>
</Grid>
Style中的Setter
Setter,属性值的设置器,给属性赋值的时候一般都采用“属性名=属性值”的形式。Setter类的Property属性用来指明想为目标的哪个属性赋值;Setter类的Value属性则是提供的属性值。
Style中的Trigger
Trigger,触发器,即当某些条件满足时会触发一个行为(比如某些值的变化或动画的发生等),主要类型有:
- 事件触发型的EventTrigger
- 数据变化触发型的Trigger/DataTrigger
- 多条件触发型的MultiTrigger/MultiDataTrigger
Trigger类是最基本的触发器。类似于Setter,Trigger也有Property和Value这两个属性,Property是Trigger 关注的属性名称,Value是触发条件。
Trigger类还有一个Setters属性,此属性值是一组Setter,一旦触发条件被满足,这组Setter的“属性一值”就会被应用,触发条件不再满足后,各属性值会被还原。
一个针对CheckBox的Style,当CheckBox的IsChecked属性为true的时候前景色和字体会改变。XAML代码如下:
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="185.425" Width="300">
<Window.Resources>
<Style TargetType="CheckBox">
<!--Triggers不是Style的内容属性,<Style.Triggers>...</Style.Triggers>这层标签不能省略-->
<Style.Triggers>
<Trigger Property="IsChecked" Value="true">
<!--Trigger的Setters属性是Trigger的内容属性,<Trigger.Setters.…</Trigger.Seters>这层标签可以省略-->
<!--<Trigger.Setters>-->
<Setter Property="FontSize" Value="20"/>
<Setter Property="Foreground" Value="Orange"/>
<!--</Trigger.Setters>-->
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<CheckBox Content="悄悄的我走了" Margin="5"/>
<CheckBox Content="正如我悄悄的来" Margin="5,0"/>
<CheckBox Content="我挥一挥衣袖" Margin="5"/>
<CheckBox Content="不带走一片云彩" Margin="5,0"/>
</StackPanel>
</Window>
MultiTrigger必须多个条件同时成立时才会被触发,比Trigger多了一个Conditions属性,需要同时成立的条件就存储在这个集合中。改动上面的例子,要求同时满足CheckBox被选中且Content为“正如我悄悄的来”时才会被触发,XAML代码如下(仅Style部分):
<Style TargetType="CheckBox">
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsChecked" Value="true"/>
<Condition Property="Content" Value="正如我悄悄的来"/>
</MultiTrigger.Conditions>
<Setter Property="FontSize" Value="20"/>
<Setter Property="Foreground" Value="Orange"/>
</MultiTrigger>
</Style.Triggers>
</Style>
效果如下:
Template扩展:
很多时候数据是以XML形式存储的,DataTemplate具有直接把XML数据结点当作目标对象的功能——XML数据中的元素名(标签名)可以作为DataType,元素的子结点和Attribute可以使用XPath来访问。下面的代码使用XmlDataProvider作为数据源,代码如下:
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp"
xmlns:c="clr-namespace:System.Collections;assembly=mscorlib"
Title="MainWindow" Height="500" Width="333.035">
<Window.Resources>
<!--Data Template-->
<DataTemplate DataType="Unit">
<Grid>
<StackPanel Orientation="Horizontal">
<Grid>
<Rectangle Stroke="Yellow" Fill="Orange" Width="{Binding XPath=@Price}"/>
<TextBlock Text="{Binding XPath=@Year}"/>
</Grid>
<TextBlock Text="{Binding XPath=@Price}" Margin="5.0"/>
</StackPanel>
</Grid>
</DataTemplate>
<!--数据源-->
<XmlDataProvider x:Key="ds" XPath="Units/Unit">
<x:XData>
<Units xmlns="">
<Unit Year="2001" Price="100"/>
<Unit Year="2001" Price="120"/>
<Unit Year="2001" Price="140"/>
<Unit Year="2001" Price="160"/>
<Unit Year="2001" Price="180"/>
<Unit Year="2001" Price="200"/>
</Units>
</x:XData>
</XmlDataProvider>
</Window.Resources>
<StackPanel>
<ListBox ItemsSource="{Binding Source={StaticResource ds}}"/>
<ComboBox ItemsSource="{Binding Source={StaticResource ds}}" Margin="5"/>
</StackPanel>
</Window>
显示层级数据的模板HierarchicalDataTemplate
XML最大的优势是可以方便地表示带有层级的数据,WPF准备了TreeView和Menultem控件用来显示层级数据,能够帮助层级控件显示层级数据的模板是HierarchicalDataTemplate。第一个例子是使用TreeView显示多层级、不同类型数据,需要为每种数据设计一个模板,有机会使每种数据类型有自己独特的外观。数据保存在项目根目录的Data.xml文件中,内容如下:
<?xml version="1.0" encoding="utf-8" ?>
<Data xmlns="">
<Grade Name="一年级">
<Class Name="甲班">
<Group Name="A组"/>
<Group Name="B组"/>
<Group Name="C组"/>
</Class>
<Class Name="乙班">
<Group Name="A组"/>
<Group Name="B组"/>
<Group Name="C组"/>
</Class>
</Grade>
<Grade Name="二年级">
<Class Name="甲班">
<Group Name="A组"/>
<Group Name="B组"/>
<Group Name="C组"/>
</Class>
<Class Name="乙班">
<Group Name="A组"/>
<Group Name="B组"/>
<Group Name="C组"/>
</Class>
</Grade>
</Data>
程序的XAML代码如下:
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="400" Width="333.035">
<Window.Resources>
<!--数据源-->
<XmlDataProvider x:Key="ds" Source="Data.xml" XPath="Data/Grade"/>
<!--年级模板-->
<HierarchicalDataTemplate DataType="Grade" ItemsSource="{Binding XPath=Class}">
<TextBlock Text="{Binding XPath=@Name}"/>
</HierarchicalDataTemplate>
<!--班级模板-->
<HierarchicalDataTemplate DataType="Class" ItemsSource="{Binding XPath=Group}">
<RadioButton Content="{Binding XPath=@Name}" GroupName="gn"/>
</HierarchicalDataTemplate>
<!--小组模板-->
<HierarchicalDataTemplate DataType="Group" ItemsSource="{Binding XPath=Student}">
<CheckBox Content="{Binding XPath=@Name}"/>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid>
<TreeView Margin="5" ItemsSource="{Binding Source={StaticResource ds}}"/>
</Grid>
</Window>
效果如下:
第二个例子是同一种数据类型的嵌套结构,这种情况下只需设计一个HierarchicalDataTemplate,它会产生自动迭代应用的效果。数据仍然存放在Data.xml文件中,数据全都是Operation类型:
<?xml version="1.0" encoding="utf-8" ?>
<Data xmlns="">
<Operation Name="文件" Gesture="F">
<Operation Name="新建" Gesture="N">
<Operation Name="项目" Gesture="Control+P"/>
<Operation Name="网站" Gesture="Control+W"/>
<Operation Name="文档" Gesture="Control+D"/>
</Operation>
<Operation Name="保存" Gesture="S"/>
<Operation Name="打印" Gesture="P"/>
<Operation Name="退出" Gesture="X"/>
</Operation>
<Operation Name="编辑" Gesture="E">
<Operation Name="拷贝" Gesture="Control+C"/>
<Operation Name="剪切" Gesture="Control+X"/>
<Operation Name="粘贴" Gesture="Control+V"/>
</Operation>
</Data>
程序的XAML代码如下:
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="300" Width="300">
<Window.Resources>
<!--数据源-->
<XmlDataProvider x:Key="ds" Source="Data.xml" XPath="Data/Operation"/>
<!--Operation 模板-->
<HierarchicalDataTemplate DataType="Operation" ItemsSource="{Binding XPath=Operation}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding XPath=@Name}" Margin="10,0"/>
<TextBlock Text="{Binding XPath=@Gesture}"/>
</StackPanel>
</HierarchicalDataTemplate>
</Window.Resources>
<StackPanel MenuItem.Click="StackPanel_Click">
<Menu ItemsSource="{Binding Source={StaticResource ds}}"/>
</StackPanel>
</Window>
HierarchicalDataTemplate的作用目标是Menultem的Header,可以从被单击Menultem的Header中取出XML数据。事件处理器代码如下:
private void StackPanel_Click(object sender, RoutedEventArgs e)
{
MenuItem mi = e.OriginalSource as MenuItem;
XmlElement xe = mi.Header as XmlElement;
MessageBox.Show(xe.Attributes["Name"].Value);
}
效果如下:
Note:可以维护一个CommandHelper类,根据拿到的数据来决定执行什么RoutedCommand。
从外界访问Template内部的控件及其属性值
由ControlTemplate或DataTemplate生成的控件都是“由Template生成的控件”,ControlTemplate和DataTemplate两个类均派生自FrameworkTemplate类,有个名为FindName的方法可以检索其内部控件。
检索ControlTemplate生成的控件
设计一个ControlTemplate并把它应用在一个UserControl上,界面上还有一个Button,在它的Click事件处理器中检索由ControlTemplate生成的代码。
程序的XAML代码如下:
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="160" Width="300">
<Window.Resources>
<ControlTemplate x:Key="cTmp">
<StackPanel Background="Orange">
<TextBox x:Name="textBox1" Margin="6"/>
<TextBox x:Name="textBox2" Margin="6,0"/>
<TextBox x:Name="textBox3" Margin="6"/>
</StackPanel>
</ControlTemplate>
</Window.Resources>
<StackPanel Background="Yellow">
<UserControl x:Name="uc" Template="{ StaticResource cTmp}" Margin="5"/>
<Button Content="Find by Name" Width="120" Height="30" Click="Button_Click"/>
</StackPanel>
</Window>
后台代码如下:
private void Button_Click(object sender, RoutedEventArgs e)
{
TextBox tb = this.uc.Template.FindName("textBox1", this.uc) as TextBox;
tb.Text = "Hello WPF";
StackPanel sp = tb.Parent as StackPanel;
(sp.Children[1] as TextBox).Text = "Hello ControlTemplate,I can find you!";
}
Trigger扩展:
由数据触发的DataTrigger
基于数据执行某些判断可以考虑使用DataTrigger,DataTrigger对象的Binding属性会把数据源源不断送过来,一旦送来的值与Value属性一致DataTrigger即被触发。
下面例子中,当TextBox的Text长度小于7个字符时其Border会保持红色,XAML代码如下:
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp"
Title="MainWindow" Height="123.435" Width="204.297">
<Window.Resources>
<local:L2BConverter x:Key="cvtr"/>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{ Binding RelativeSource={x:Static RelativeSource.Self}, Path=Text.Length, Converter={ StaticResource cvtr}}" Value="false">
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="BorderThickness" Value="1"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<TextBox Margin="5"/>
<TextBox Margin="5,0"/>
<TextBox Margin="5"/>
</StackPanel>
</Window>
为了将控件自己作为数据源需要使用RelativeSource,如果不明确指出Source时Binding会把控件的DataContext属性当作数据源而非把控件自身当作数据源。
Binding的Path被设置为Text.Length,字符串的长度是一个具体的数字,基于这个长度值做判断时需要用到Converter,创建如下的Converter:
//经Converter转换后,长度值会转换成bool类型值,DataTrigger的Value被设置为false。
public class L2BConverter : IValueConverter
{
public object Convert(object value,Type targetype,object parameter, CultureInfo culture)
{
int textLength = (int)value;
return textLength > 6 ? true : false;
}
public object ConvertBack(object value, Type targetype, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
效果如下:
多数据条件触发的MultiDataTrigger
遇到要求多个数据条件同时满足时才能触发变化的需求,此时可以考虑使用MultiDataTrigger。
用户界面上使用ListBox显示了一列Student数据,当Student对象同时满足ID为2、Name为Tom的时候条目就高亮显示,示例的XAML代码如下:
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="123.435" Width="300">
<Window.Resources>
<Style TargetType="ListBoxItem">
<!--使用Style设置DataTemplate-->
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ID}" Width="60"/>
<TextBlock Text="{Binding Name}" Width="120"/>
<TextBlock Text="{Binding Age}" Width="60"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
<!--MultiDataTrigger-->
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=ID}" Value="2"/>
<Condition Binding="{Binding Path=Name}" Value="Tom"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Background" Value="Orange"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<ListBox x:Name="listBoxStudent" Margin="5"/>
</StackPanel>
</Window>
后台代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<Student> studentList = new List<Student>()
{new Student(){ ID=1, Name="Tim", Age=21},
new Student(){ ID=2, Name="Tom", Age=22 }};
this.listBoxStudent.ItemsSource = studentList;
}
}
public class Student
{
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
效果如下:
由事件触发的EventTrigger
EventTrigger是触发器中最特殊的一个,它是由事件来触发,被触发后执行一段动画,U1层的动画效果往往与EventTrigger相关联。
创建了一个针对Button的Style,这个Style包含两个EventTrigger,一个由MouseEnter事件触发,另一个由MouseLeave事件触发。XAML代码如下:
<!--由事件触发的EventTrigger-->
<Style TargetType="Button">
<Style.Triggers>
<!--鼠标进入-->
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="150" Duration="0:0:0.2" Storyboard.TargetProperty="Width"/>
<DoubleAnimation To="150" Duration="0:0:0.2" Storyboard.TargetProperty="Height"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<!--鼠标离开-->
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Width"/>
<DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Height"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
效果如下: