WPF学习(三)
文章目录
- 一 、Template
- 1.1 重点掌握
- 1.2 my example
- 二、 Resource
- 2.1 重点掌握
- 2.2 三种引用方式
- 三、关键帧
一 、Template
1.1 重点掌握
在WPF(Windows Presentation Foundation)中,ControlTemplate
是定义控件外观和行为的核心机制。一个模板可以包含以下类型的元素和功能:
一、可视化元素
模板的核心是定义控件的视觉结构
,可包含:
-
布局容器
Grid
、StackPanel
、Canvas
、DockPanel
等,用于组织子元素的排列方式。- 示例:
<ControlTemplate TargetType="Button"><Grid><!-- 按钮内容将在此处显示 --></Grid> </ControlTemplate>
-
图形元素
Rectangle
、Ellipse
、Path
、Line
等形状,用于创建自定义外观。- 示例:
<Rectangle x:Name="Background" Fill="Blue" />
-
内容展示
ContentPresenter
:显示控件的Content
属性(如按钮的文本)。ItemsPresenter
:用于ItemsControl
(如ListBox
)显示子项集合。- 示例:
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
-
装饰器
Border
、DropShadowEffect
、BlurEffect
等,用于添加边框、阴影或视觉效果。- 示例:
<Border BorderBrush="Black" BorderThickness="1" CornerRadius="4"><!-- 内部元素 --> </Border>
二、触发器(Triggers)
用于根据控件状态改变外观,包括:
-
属性触发器(PropertyTrigger)
- 基于控件属性值触发(如
IsMouseOver
、IsPressed
)。 - 示例:
<Trigger Property="IsMouseOver" Value="True"><Setter TargetName="Background" Property="Fill" Value="LightBlue" /> </Trigger>
- 基于控件属性值触发(如
-
事件触发器(EventTrigger)
- 基于事件触发动画(如
MouseEnter
、Loaded
)。 - 示例:
<EventTrigger RoutedEvent="Button.Click"><BeginStoryboard><Storyboard><!-- 动画定义 --></Storyboard></BeginStoryboard> </EventTrigger>
- 基于事件触发动画(如
-
数据触发器(DataTrigger)
- 基于绑定数据触发(需配合
DataContext
使用)。
- 基于绑定数据触发(需配合
三、动画(Animations)
通过 Storyboard
定义平滑过渡效果,可应用于:
-
属性动画:如改变颜色、大小、位置等。
示例:<DoubleAnimation Storyboard.TargetName="Background" Storyboard.TargetProperty="Width" From="0" To="100" Duration="0:0:0.5" />
-
关键帧动画:定义多个中间状态,实现更复杂的动画路径。
四、命名元素引用(x:Name)
为元素分配名称,以便在模板内部或触发器中引用:
<Rectangle x:Name="Highlight" Fill="Red" Visibility="Hidden" />
在触发器中使用:
<Trigger Property="IsSelected" Value="True"><Setter TargetName="Highlight" Property="Visibility" Value="Visible" />
</Trigger>
五、模板绑定(TemplateBinding)
将模板内元素的属性绑定到控件的属性:
<Border BorderThickness="{TemplateBinding BorderThickness}" />
常见绑定属性:Width
、Height
、Foreground
、Background
等。
六、样式与资源
-
内联样式:在模板内定义局部样式。
<Style TargetType="TextBlock"><Setter Property="FontSize" Value="14" /> </Style>
-
资源引用:使用
StaticResource
或DynamicResource
引用外部资源(如颜色、画笔)。<SolidColorBrush x:Key="ButtonHoverBrush" Color="LightBlue" /> <!-- 在模板中使用 --> <Setter Property="Background" Value="{StaticResource ButtonHoverBrush}" />
七、逻辑交互元素
-
子控件:在模板中嵌入其他控件(如
TextBox
、CheckBox
)。<CheckBox x:Name="ToggleButton" Content="选项" />
-
交互行为:通过
Behavior
(需引用System.Windows.Interactivity
)添加自定义交互逻辑。
八、模板参数(TemplatePart)
使用 TemplatePart
特性声明模板需要的特定元素,供控件逻辑使用:
[TemplatePart(Name = "PART_ContentHost", Type = typeof(FrameworkElement))]
public class CustomControl : Control
{// 控件逻辑
}
完整示例:自定义按钮模板
<ControlTemplate TargetType="Button"><Grid><!-- 背景 --><Rectangle x:Name="Background" Fill="{TemplateBinding Background}" RadiusX="4" RadiusY="4" /><!-- 内容显示 --><ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" /><!-- 鼠标悬停时的高亮效果 --><Rectangle x:Name="Highlight" Fill="LightBlue" RadiusX="4" RadiusY="4" Opacity="0" /></Grid><ControlTemplate.Triggers><!-- 鼠标悬停时显示高亮 --><Trigger Property="IsMouseOver" Value="True"><Setter TargetName="Highlight" Property="Opacity" Value="0.5" /></Trigger><!-- 点击时改变背景色 --><Trigger Property="IsPressed" Value="True"><Setter TargetName="Background" Property="Fill" Value="DarkBlue" /></Trigger></ControlTemplate.Triggers>
</ControlTemplate>
总结
ControlTemplate
可以包含几乎所有WPF元素,核心功能是:
- 定义控件的视觉结构(布局、形状、内容)
- 通过触发器实现状态驱动的外观变化
- 使用动画增强交互体验
- 通过模板绑定保持与控件属性的同步
合理使用模板,可以完全自定义任何控件的外观和行为,同时保留其原始功能。
1.2 my example
<Window x:Class="WpfApp1.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="MainWindow" Height="450" Width="800"><Grid><Grid.RowDefinitions><RowDefinition/><RowDefinition/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><Ellipse x:Name="myEllipse"><Ellipse.Fill><SolidColorBrush x:Name="ellipseBrush" Color="Red" /></Ellipse.Fill></Ellipse><Rectangle Grid.Column="1" x:Name="rectangle" Width="10"><Rectangle.Fill><SolidColorBrush Color="Red" /></Rectangle.Fill></Rectangle><Button x:Name="myButton" Grid.Row="1" Width="250" Height="50" Content="动画触发启动"><Button.Template><ControlTemplate TargetType="Button"><Border BorderBrush="Fuchsia" BorderThickness="2"><Grid><!-- 定义动画目标Rectangle --><Rectangle x:Name="rectangle" Fill="LightBlue" Width="10" Height="{TemplateBinding Height}" HorizontalAlignment="Left"/><ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/></Grid></Border><ControlTemplate.Triggers><!-- 鼠标悬停时启动动画 --><Trigger Property="IsMouseOver" Value="true"><Trigger.EnterActions><BeginStoryboard><Storyboard><DoubleAnimation Storyboard.TargetName="rectangle" Storyboard.TargetProperty="Width"Duration="0:0:1"From="10" To="250"AutoReverse="True"RepeatBehavior="Forever"/></Storyboard></BeginStoryboard></Trigger.EnterActions><!-- 鼠标离开时停止动画 --><Trigger.ExitActions><BeginStoryboard><Storyboard><DoubleAnimation Storyboard.TargetName="rectangle"Storyboard.TargetProperty="Width"Duration="0:0:0.3"To="10"/></Storyboard></BeginStoryboard></Trigger.ExitActions></Trigger></ControlTemplate.Triggers></ControlTemplate></Button.Template></Button><Grid.Triggers><EventTrigger RoutedEvent="FrameworkElement.Loaded"><BeginStoryboard><Storyboard><!-- 第一个椭圆的动画 --><ColorAnimation Storyboard.TargetName="ellipseBrush"Storyboard.TargetProperty="Color"Duration="00:00:10"From="Red" To="Black"AutoReverse="True"RepeatBehavior="Forever"SpeedRatio="10"/><DoubleAnimation Storyboard.TargetName="rectangle"Storyboard.TargetProperty="Width"Duration="00:00:10"From="10" To="200"AutoReverse="True"RepeatBehavior="Forever"SpeedRatio="5"/></Storyboard></BeginStoryboard></EventTrigger></Grid.Triggers></Grid>
</Window>
二、 Resource
在WPF中,Resources
是一种强大的机制,用于集中管理和复用应用程序中的各种资源(如样式、画笔、动画等)。以下是关于 Resources
的详细使用指南:
2.1 重点掌握
一、资源的定义与分类
资源可以定义在多个位置,按作用域分为:
-
应用程序级别:在
App.xaml
中定义,全局可用<Application.Resources><SolidColorBrush x:Key="PrimaryColor" Color="#3498DB" /> </Application.Resources>
-
窗口/控件级别:在窗口或控件的
Resources
中定义,仅在当前范围内可用<Window.Resources><Style x:Key="ButtonStyle" TargetType="Button"><Setter Property="Background" Value="{StaticResource PrimaryColor}" /></Style> </Window.Resources>
-
局部资源:在元素内部定义,仅作用于该元素及其子元素
<Grid.Resources><DataTemplate x:Key="PersonTemplate"><TextBlock Text="{Binding Name}" /></DataTemplate> </Grid.Resources>
二、常见资源类型
-
样式(Style)
统一设置控件的外观属性:<Style x:Key="TextBoxStyle" TargetType="TextBox"><Setter Property="Foreground" Value="DarkBlue" /><Setter Property="BorderBrush" Value="Gray" /> </Style>
-
画笔(Brush)
定义颜色、渐变等填充效果:<SolidColorBrush x:Key="AccentBrush" Color="Orange" /> <LinearGradientBrush x:Key="GradientBrush" StartPoint="0,0" EndPoint="1,1"><GradientStop Color="White" Offset="0" /><GradientStop Color="LightGray" Offset="1" /> </LinearGradientBrush>
-
模板(Template)
自定义控件的视觉结构:<ControlTemplate x:Key="CustomButtonTemplate" TargetType="Button"><Border Background="{TemplateBinding Background}" CornerRadius="5"><ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" /></Border> </ControlTemplate>
-
数据模板(DataTemplate)
定义数据的显示方式:<DataTemplate x:Key="EmployeeTemplate"><StackPanel Orientation="Horizontal"><TextBlock Text="{Binding Name}" Margin="5" /><TextBlock Text="{Binding Age}" Margin="5" /></StackPanel> </DataTemplate>
-
动画(Storyboard)
预定义动画效果:<Storyboard x:Key="FadeInAnimation"><DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.5" /> </Storyboard>
三、资源的引用方式
使用 StaticResource
或 DynamicResource
标记扩展引用资源:
-
静态资源(StaticResource)
在编译时解析,性能较高,适合不会动态变化的资源:<Button Style="{StaticResource ButtonStyle}" /> <Rectangle Fill="{StaticResource GradientBrush}" />
-
动态资源(DynamicResource)
在运行时动态解析,支持资源值的实时更新:<TextBlock Foreground="{DynamicResource AccentColor}" />
四、资源字典(ResourceDictionary)
将资源单独提取到 .xaml
文件中,实现跨项目共享:
-
创建资源字典文件(如
Styles.xaml
):<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"><Style x:Key="TitleText" TargetType="TextBlock"><Setter Property="FontSize" Value="24" /><Setter Property="FontWeight" Value="Bold" /></Style> </ResourceDictionary>
-
在应用程序中引用:
<Application.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="Styles.xaml" /><ResourceDictionary Source="Themes/BlueTheme.xaml" /></ResourceDictionary.MergedDictionaries></ResourceDictionary> </Application.Resources>
五、隐式资源(无Key的资源)
通过省略 x:Key
并指定 TargetType
,创建可自动应用的资源:
<Style TargetType="Button"><Setter Property="Background" Value="LightGray" /><Setter Property="Foreground" Value="Black" />
</Style>
所有未显式设置样式的 Button
都会自动应用此样式。
六、资源查找顺序
当使用 StaticResource
或 DynamicResource
引用资源时,WPF会按以下顺序查找:
- 当前元素的
Resources
集合 - 父元素的
Resources
集合(向上递归查找) - 窗口/页面的
Resources
集合 - 应用程序级别的
Resources
集合(App.xaml
) - 所有合并的资源字典
- 系统资源(如默认字体、颜色等)
七、示例:完整应用
App.xaml(定义全局资源):
<Application.Resources><SolidColorBrush x:Key="PrimaryColor" Color="#2C3E50" /><SolidColorBrush x:Key="AccentColor" Color="#E74C3C" /><Style x:Key="MainWindowStyle" TargetType="Window"><Setter Property="Background" Value="{StaticResource PrimaryColor}" /></Style>
</Application.Resources>
MainWindow.xaml(使用资源):
<Window x:Class="MyApp.MainWindow"Style="{StaticResource MainWindowStyle}"><Window.Resources><Style x:Key="TitleText" TargetType="TextBlock"><Setter Property="FontSize" Value="24" /><Setter Property="Foreground" Value="{StaticResource AccentColor}" /></Style></Window.Resources><Grid><TextBlock Style="{StaticResource TitleText}" Text="欢迎使用我的应用" /><Button Content="点击" Background="{StaticResource AccentColor}" /></Grid>
</Window>
八、注意事项
- 资源键必须唯一:同一范围内不能有重复的
x:Key
- 静态资源 vs 动态资源:
- 静态资源在初始化时解析,修改资源不会影响已应用的元素
- 动态资源会实时更新,但性能开销略高
- 避免循环引用:资源间的引用不能形成闭环
- 资源优先级:局部资源会覆盖全局资源
合理使用 Resources
可以大幅提高代码的可维护性和复用性,使UI设计更加统一和灵活。
2.2 三种引用方式
要使用在 Resources
中定义的 mybutton
样式,你需要通过 Style
属性将其应用到 Button 控件上。以下是具体的实现方法:
方法1:显式引用命名样式
如果在资源中定义了带 x:Key
的样式(如 mybutton
),需要通过 Style="{StaticResource mybutton}"
显式应用:
<Window.Resources><!-- 定义名为"mybutton"的样式 --><Style x:Key="mybutton" TargetType="Button"><Setter Property="Background" Value="LightBlue" /><Setter Property="Foreground" Value="DarkBlue" /><Setter Property="FontSize" Value="16" /></Style>
</Window.Resources><Grid><!-- 应用自定义样式 --><Button Style="{StaticResource mybutton}" Content="自定义按钮" />
</Grid>
方法2:隐式应用样式(无 x:Key
)
如果希望所有 Button 自动应用该样式,可以省略 x:Key
只保留 TargetType
:
<Window.Resources><!-- 所有Button将自动应用此样式 --><Style TargetType="Button"><Setter Property="Background" Value="LightBlue" /><Setter Property="Foreground" Value="DarkBlue" /><Setter Property="FontSize" Value="16" /></Style>
</Window.Resources><Grid><!-- 无需指定Style属性,自动应用上面的样式 --><Button Content="自动应用样式的按钮" />
</Grid>
方法3:基于现有样式扩展
如果想在默认 Button 样式基础上扩展,可以使用 BasedOn
属性:
<Window.Resources><Style x:Key="mybutton" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}"><Setter Property="Background" Value="LightBlue" /><Setter Property="Foreground" Value="DarkBlue" /></Style>
</Window.Resources><Grid><Button Style="{StaticResource mybutton}" Content="扩展默认样式的按钮" />
</Grid>
关键点说明
-
x:Key
的作用:- 有
x:Key
(如x:Key="mybutton"
):需显式引用 - 无
x:Key
:隐式应用到所有TargetType
类型的控件
- 有
-
资源作用域:
- 在
<Window.Resources>
中定义:仅当前窗口可用 - 在
<Application.Resources>
中定义:全局所有窗口可用
- 在
-
引用语法:
StaticResource
:编译时解析(推荐)DynamicResource
:运行时动态解析(适用于需要实时更新的场景)
完整示例
以下是一个完整的窗口示例,包含自定义 Button 样式的定义和使用:
<Window x:Class="WpfApp1.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="自定义按钮样式" Height="300" Width="400"><Window.Resources><!-- 自定义按钮样式 --><Style x:Key="mybutton" TargetType="Button"><Setter Property="Background" Value="#3498DB" /><Setter Property="Foreground" Value="White" /><Setter Property="FontSize" Value="14" /><Setter Property="Padding" Value="8,4" /><Setter Property="BorderThickness" Value="0" /><Setter Property="CornerRadius" Value="4" /><!-- 鼠标悬停效果 --><Style.Triggers><Trigger Property="IsMouseOver" Value="True"><Setter Property="Background" Value="#2980B9" /></Trigger></Style.Triggers></Style></Window.Resources><Grid><!-- 使用自定义样式的按钮 --><Button Style="{StaticResource mybutton}" Content="点击我" HorizontalAlignment="Center" VerticalAlignment="Center" /><!-- 普通按钮(未应用样式) --><Button Content="普通按钮" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,20" /></Grid>
</Window>
常见问题
-
样式不生效:
- 检查
x:Key
拼写是否正确 - 确保
TargetType
与控件类型匹配(如TargetType="Button"
)
- 检查
-
全局应用样式:
将样式定义移至App.xaml
的<Application.Resources>
中:<Application.Resources><Style x:Key="mybutton" TargetType="Button"><!-- 样式内容 --></Style> </Application.Resources>
通过上述方法,你可以灵活地复用自定义的 Button 样式,提高代码的可维护性和一致性。
三、关键帧
在WPF中,含有关键帧的时间线(KeyFrame Animation) 和不含关键帧的时间线(基本动画) 主要区别在于动画的复杂度和控制精度。以下是具体对比:
特性 | 基本动画 | 关键帧动画 |
---|---|---|
变化路径 | 线性(直线) | 支持非线性(曲线、突变) |
控制点数量 | 2个(起始值和结束值) | ≥2个(可定义任意数量关键帧) |
时间控制 | 整体持续时间(Duration) | 每个关键帧可单独指定时间 |
插值方式 | 固定线性插值 | 支持线性、曲线、离散等多种方式 |
复杂度 | 简单 | 高(适合复杂动画) |
XAML代码量 | 少 | 多(需要定义多个关键帧) |
一、基本动画(不含关键帧)
特点
-
简单线性变化
从起始值(From
)到结束值(To
)或相对变化值(By
)进行线性插值。
示例:<DoubleAnimation From="0" To="100" Duration="0:0:1" Storyboard.TargetProperty="Width" />
-
单一变化路径
只支持直线过渡,无法定义复杂的变化曲线。 -
适用场景
- 简单的淡入淡出、大小缩放、位置移动等线性变化。
二、关键帧动画(含有关键帧)
特点
-
多阶段复杂变化
通过定义多个关键帧(KeyFrame) 指定不同时间点的属性值,支持非线性变化。
示例:<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Width" Duration="0:0:2"><LinearDoubleKeyFrame Value="0" KeyTime="0:0:0" /> <!-- 0秒时宽度为0 --><LinearDoubleKeyFrame Value="100" KeyTime="0:0:1" /> <!-- 1秒时宽度为100 --><SplineDoubleKeyFrame Value="150" KeyTime="0:0:1.5" <!-- 1.5秒时宽度为150(使用曲线插值) -->KeySpline="0.5,0 0.7,1" /> <!-- 定义贝塞尔曲线,控制加速/减速 --><DiscreteDoubleKeyFrame Value="200" KeyTime="0:0:2" /> <!-- 2秒时立即跳转到200 --> </DoubleAnimationUsingKeyFrames>
-
多种插值方式
- LinearKeyFrame:线性插值(匀速变化)
- SplineKeyFrame:使用贝塞尔曲线插值(可自定义加速/减速)
- DiscreteKeyFrame:离散变化(瞬间跳转)
-
精确时间控制
每个关键帧都可以指定精确的KeyTime
,实现复杂的时间序列。 -
适用场景
- 不规则运动(如弹跳、弹性效果)
- 多阶段动画(如先加速后减速)
- 复杂过渡效果(如模拟物理运动)
三、核心区别对比表
特性 | 基本动画 | 关键帧动画 |
---|---|---|
变化路径 | 线性(直线) | 支持非线性(曲线、突变) |
控制点数量 | 2个(起始值和结束值) | ≥2个(可定义任意数量关键帧) |
时间控制 | 整体持续时间(Duration) | 每个关键帧可单独指定时间 |
插值方式 | 固定线性插值 | 支持线性、曲线、离散等多种方式 |
复杂度 | 简单 | 高(适合复杂动画) |
XAML代码量 | 少 | 多(需要定义多个关键帧) |
四、何时选择哪种方式?
-
选择基本动画:
当动画是简单的线性变化,且不需要精细控制中间过程时(如淡入淡出、匀速移动)。 -
选择关键帧动画:
- 需要非线性变化(如物体弹跳、弹性效果)。
- 需要在特定时间点触发特定值(如动画的暂停、跳跃)。
- 需要组合多种变化方式(如先加速后减速)。
五、示例对比
1. 基本动画:匀速淡入
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:1" />
2. 关键帧动画:弹性淡入(先过度再回弹)
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Duration="0:0:1.5"><LinearDoubleKeyFrame Value="0" KeyTime="0:0:0" /><SplineDoubleKeyFrame Value="1.2" KeyTime="0:0:0.8" KeySpline="0.5,0 0.7,1" /> <!-- 先超过目标值(1.2) --><SplineDoubleKeyFrame Value="1" KeyTime="0:0:1.5" KeySpline="0.3,0 0.5,1" /> <!-- 回弹到最终值(1) -->
</DoubleAnimationUsingKeyFrames>
总结
关键帧动画是基本动画的超集,提供了更强大的控制能力,但也增加了代码复杂度。根据动画需求的简单或复杂程度,选择合适的方式可以在保证效果的同时优化代码结构。