快速入门
1.创建一个WPF项目
框架选择.net 8.0及以上长期支持。
双击项目文件,里面会有一些代码,主要是一些配置信息:
2.App.xaml与Application类
xaml类型的文件包含两部分,一部分以.xaml扩展名结尾的前端代码,另一部分以.xaml.cs结尾的后端代码,通常我们也把后端代码称为隐藏代码。
前端代码:
在xaml代码中,我们可以看到有一个<App1ication>的标签,同时在里面还有一句话x:class="TpfApp1.App”它定义一个名叫App的类型,这个类型位于命令空间WpfApp1之中,与后端代码的namespace WpfApp1保持致。我们可以将x:Class和c#里面的class关键词看成是同一个东西,都表示定义某个类型,并且指定 xam1 文件后端隐藏代码是哪个类。
微软把WPF中经常使用的功能都封装在 Application 类中了。那么下面我们详细介绍一下Application
3.Application生命周期钩子
1.Application的父类的是DispatcherObject类,它是WPF中的一个重要基类,它为WPF对象提供了与线程调度器(Dispatcher)相关的基本功能。
2.Application有一个Current属性,他代表的是我们当前应用程序的当前对象。
(1)OnStartup() - 应用程序启动入口
protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); // 必须调用基类方法 }触发时机:在
Application.Run()
之后,主窗口显示之前
(2)OnActivated() - 应用程序获得焦点
protected override void OnActivated(EventArgs e) { base.OnActivated(e); }触发条件:
从其他应用切换回本应用
系统唤醒后恢复
第一次启动时(在OnStartup之后)
(3)OnDeactivated() - 应用程序失去焦点
protected override void OnDeactivated(EventArgs e) { base.OnDeactivated(e); //基类调用 // 典型场景: // 1. 暂停耗性能的后台任务 // 2. 保存临时状态 Debug.WriteLine("应用程序进入后台状态"); }注意:与窗口的
Activated/Deactivated
事件不同,这是应用级别的状态变化
(4) OnExit() - 应用程序退出清理
protected override void OnExit(ExitEventArgs e)
{
// 执行资源释放(会在所有窗口关闭后调用)
DatabaseConnection.Cleanup();
Logger.Flush();
base.OnExit(e); // 基类调用必须放在最后
// 可通过e.ApplicationExitCode设置退出码
e.ApplicationExitCode = 0;
}关键特性:
最后机会释放非托管资源
可以访问
Application.Current.Properties
字典中的全局状态无法取消退出操作(如需取消应处理
SessionEnding
)
完整生命周期顺序示例:
App构造函数
↓
OnStartup()
↓
主窗口显示
↓
OnActivated() ←首次激活
↓
[可能多次] OnDeactivated() ↔ OnActivated()
↓
OnExit()
4.Window窗体的生命周期
window窗体实际上是一个控件。每个window窗体的生命周期是独立的。
完整的生命周期顺序:
-
构造函数 →
InitializeComponent()
-
Initialized
事件 -
OnSourceInitialized()
-
Loaded
事件 -
OnContentRendered()
-
(多次)
Activated
↔Deactivated
-
Closing
事件 (可取消) -
OnClosing()
-
Closed
事件 -
窗口对象销毁
初始化阶段:
(1)构造函数
public MainWindow()
{
InitializeComponent(); // 必须调用以加载XAML定义的组件
// 其他初始化代码
}
(2)Initialized 事件
-
当窗口完成初始化时触发
-
此时所有XAML元素已加载但窗口尚未显示
this.Initialized += (s, e) => { /* 初始化后逻辑 */ };
加载阶段:
(3) OnSourceInitialized()
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
// 窗口句柄(hWnd)已创建,可进行Win32互操作
// 常用场景:添加系统托盘图标、注册热键等
}
(4)Loaded() 事件
-
窗口布局已完成,所有元素已呈现
-
适合执行依赖可视化树的逻辑
this.Loaded += (s, e) => { /* 加载完成后的操作 */ };
显示阶段
(5) OnContentRendered()
protected override void OnContentRendered(EventArgs e)
{
base.OnContentRendered(e);
// 所有内容(包括异步加载的内容)已完成渲染
// 适合执行动画启动、自动聚焦等操作
}
激活/停用阶段
(6) Activated/Deactivated 事件
this.Activated += (s, e) => { /* 窗口获得焦点 */ };
this.Deactivated += (s, e) => { /* 窗口失去焦点 */ };
关闭阶段
(7)Closing 事件
-
可取消的关闭前事件
this.Closing += (s, e) =>
{
if(hasUnsavedChanges)
{
e.Cancel = true; // 阻止关闭
ShowSavePrompt();
}
};
(8)Closed 事件
this.Closed += (s, e) =>
{
// 窗口已关闭,执行最终清理
// 注意:此时窗口对象仍存在但已不可见
};
窗口的常用属性
1.lcon 指定窗口的图标;
2.Title 指定窗口的标题;
3.WindowStyle 指定窗口样式,有4个取值:
- None,无边框;(当ResizeMode属性为NoResize时,仅剩下窗口核心。)*这个工作中用的比较多,可以自定义边框。
- SingleBorderWindow,单边框【默认】;
- ThreeDBorderWindow,3D边框:
- ToolBorderWindow,工具箱窗口
4.ResizeMode 是指定大小调节样式,有4个取值:
- NoResize,不可调节,同时没有最大化最小化按钮;
- CanMinimize,不可调节。但可以最小化;(此时最大化按钮不可用)
- CanResize,可调节【默认】
- CanResizeWithGrid,可根据网格调节;(窗口右下脚显示可调节网格)
5.TopMost 调节窗口的前后顺序,属性值为true时,窗口位于最前。TopMost值为true的窗口,位于TopMost值为false的窗口之前;TopMost值都为true的窗口,获得焦点的窗口位于前
6.Width,Height:分别表示窗口的宽度和高度,称为“尺寸属性”
7.MaxWidth、MinWidth、MaxHeight、MinHeight,分别表示窗口最大宽度、最小宽度、最大高度、最小高度。可以通过得到和更改这些属性值,来获取和改变窗口的大小和长宽范围。
8.ActualWidth、ActualHeight,分别表示窗口的实际宽度和实际高度,称为“实际尺寸属性”。实际尺寸属性是根据当前窗口大小、最小化时窗口大小和最大化时窗口大小来计算得到的,其值是只读的,也就是说,不能通过改变ActualWidth、ActualHeight的值来更改窗口大小。
9.Visibility,窗口可见性,有3个枚举值:
- Visiable,可见;
- Hidden,隐藏;
- Collapsed,折叠。虽然窗口类认为Collapsed与Hidden一样,但二者区别在于,Hidden仅仅将元素设为不可见,但是元素在画面上依然占有空间;而Collapsed,在不可视的基础上,能将元素在画面上的占位符清除,元素彻底不影响画面。
10.WindowState,窗口状态属性,有3个枚举值:
- Normal,正常:
- Maximized,最大化:
- Minimized,最小化;
11.WindowStartupLocation 窗口启动时的位置。值:CenterScreen(居中)。
程序退出
1.Close():关闭当前窗口
在WPF应用程序的关闭是有ShutdownMode属性设置,具有3中枚举类型的值:
- 1)OnLastWindowClose(默认值)---应用程序最后一个窗体关闭时关闭应用程序
- 2)OnMainWindowClose---应用程序主窗体关闭时关闭应用程序(开发中用的多)
- 3)OnExplicitShutdown---显示调用关闭
这种情况是指当 shutdownMode 值为 0nMainwindowclose 时关闭主窗体,如果有多余线程此方式不适用。
2.Application.Current.Shutdown()
只关掉了UI而后台进程没有关掉,直到所有的后台线程结束才算真的结束。
3.Environment.Exit(0)
强制退出,即使有其他的线程没有结束。不过它不会执行代码块的finally块(如果有的话),但资源清理还是要进行的。**它是最常见的退出当前进程的方法之一
4.Process对象实例.Kill()
var curentProcess=Process.GetCurentProcess():
currentProcess.Ki11():
从名字也可以看出来,直接杀掉,不给喘息喘息机会,Ki方法会直接结束整个进程,不进行常规资源清理(什么finally块等....)
补充知识:
样式
样式的应用方式
样式(Style)是一种强大的功能,它允许您集中定义控件的属性值并在多个控件之间共享这些设置,从而实现一致的外观和感觉。
1.隐式样式(自动应用于所有指定类型的控件)
<Window.Resources>
<Style TargetType="Button">
<!-- 样式设置 -->
</Style>
</Window.Resources>
2.显式样式(通过 Key 引用)
<Window.Resources>
<Style x:Key="SpecialButtonStyle" TargetType="Button">
<!-- 样式设置 -->
</Style>
</Window.Resources>
<!--使用样式--><Button Style="{StaticResource SpecialButtonStyle}" Content="Click Me"/>
3.基于现有样式的继承
<Style x:Key="BaseButtonStyle" TargetType="Button">
<Setter Property="Background" Value="LightGray"/>
</Style><Style x:Key="DerivedButtonStyle" BasedOn="{StaticResource BaseButtonStyle}">
<Setter Property="Foreground" Value="Red"/>
</Style>
样式触发器:
1. 属性触发器
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Gold"/>
<Setter Property="Foreground" Value="Black"/>
</Trigger>
</Style.Triggers>
</Style>
2. 数据触发器
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding IsValid}" Value="False">
<Setter Property="Background" Value="Pink"/>
</DataTrigger>
</Style.Triggers>
</Style>
触发器(Trigger)
触发器是一种条件规则,当指定条件满足时,会自动应用一组属性更改(Setter)。当条件不再满足时,这些更改会自动还原。
特点:
-
声明式编程:完全在 XAML 中定义,无需编写 C# 代码
-
自动状态管理:条件满足时应用,不满足时自动恢复
-
多种类型:针对不同场景有多种触发器类型
1、属性触发器 (Property Trigger)
最基础的触发器类型,监视单个依赖属性的值变化。
语法结构:
<Trigger Property="依赖属性" Value="触发值">
<Setter Property="要修改的属性" Value="新值"/>
<!-- 可以有多个Setter -->
</Trigger>
工作原理:
-
持续监视
IsMouseOver
属性 -
当值变为
True
(鼠标进入)时应用Setter -
当值变为
False
(鼠标离开)时自动恢复原状
2、数据触发器 (DataTrigger)
基于任何绑定数据的值变化触发,而不仅仅是依赖属性。
语法结构:
<DataTrigger Binding="{Binding 路径}" Value="触发值">
<Setter Property="要修改的属性" Value="新值"/>
</DataTrigger>
3、多条件触发器 (MultiTrigger & MultiDataTrigger)
需要多个条件同时满足时才触发。
MultiTrigger 示例:
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/> <!-- 条件1:鼠标悬停 -->
<Condition Property="IsEnabled" Value="True"/> <!-- 条件2:控件启用 -->
</MultiTrigger.Conditions>
<Setter Property="Background" Value="LightGreen"/> <!-- 效果:变浅绿色背景 -->
</MultiTrigger>
工作原理:
-
同时监控两个属性:
-
鼠标是否悬停在控件上 (
IsMouseOver
) -
控件是否处于启用状态 (
IsEnabled
)
-
-
只有当两个条件同时为True时:
-
自动把背景色改成浅绿色
-
-
任意一个条件不满足时:
-
自动恢复原来的背景色
-
MultiDataTrigger 示例:
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsVIP}" Value="True"/> <!-- 条件1:是VIP用户 -->
<Condition Binding="{Binding AccountActive}" Value="True"/> <!-- 条件2:账号活跃 -->
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="Gold"/> <!-- 效果:变金色背景 -->
</MultiDataTrigger>
工作原理:
-
同时监控两个数据绑定:
-
用户是否是VIP (
IsVIP
) -
账号是否活跃 (
AccountActive
)
-
-
只有当两个数据值都为True时:
-
自动把背景色改成金色
-
-
任意一个数据变为False时:
-
自动恢复原来的背景色
-
MultiDataTrigger和MultiTrigge区别
特性 | MultiTrigger | MultiDataTrigger |
---|---|---|
监控对象 | 控件的依赖属性(如IsEnabled) | 任何绑定数据(如ViewModel的属性) |
条件写法 | Property="控件属性" | Binding="{Binding 数据属性}" |
典型用途 | 处理UI交互状态组合 | 响应业务数据逻辑组合 |
4、事件触发器 (EventTrigger)
响应路由事件,通常用于启动动画。
触发器的应用位置
1. 样式(Style)中的触发器
<Style TargetType="Button">
<Style.Triggers>
<!-- 各种触发器 -->
</Style.Triggers>
</Style>
2. 控件模板(ControlTemplate)中的触发器
<ControlTemplate TargetType="Button">
<Border x:Name="border" Background="LightBlue">
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="border" Property="Background" Value="DarkBlue"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
3.数据模板(DataTemplate)中的触发器
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
布局控制
在WPF中,布局的方式十分丰富,有按表格布局的Grid和UniformGrid栅格控件,有类似Winform拖放的Canvas控件,有按照垂直或水平排列的StackPanel(堆积面板)控件,也有按照东西南北中方位排列的DockPanel控件,还有以瀑布流方式WrapPanel(换行面板)控件,以及按Tab页切换显示的TabControl控件。
这些布局控件都有一个共性,即可以在里面放多个内容控件。于是它们之间就有了共同的Children属性,微软将它们抽象成Panel基类,并让这个基类继承于FrameworkElement 类。
那么,WPF提供了哪些常用的布局控件呢?
控件名称 | 布局方式 |
Grid | 网格,根据自定义行和列来设置控件的布局 |
StackPanel | 栈式面板,包含的元素在竖直或水平方向排成一条直线 |
WrapPanel | 自动折行面板,包含的元素在排满一行后,自动换行 |
DockPanel | 泊靠式面板,内部的元素可以选择泊靠方向 |
UniformGrid | 网格,UniformGrid就是Grid的简化版,每个单元格的大小相同 |
Canvas | 画布,内部元素根据像素为单位绝对坐标进行定位 |
Border | 装饰的控件,此控件用于绘制边框及背景,在Border中只能有一个子控件 |
这里面除了Border控件,其它控件都继承于Panel基类,下一节,我们将介绍Panel类
Panel基类
WPF 包含一套全面的派生面板实现,可支持许多复杂的布局。 这些派生类公开可实现大部分标准用户界面 (UI)方案的属性和方法。 如果开发者找不到满足其需求的子排列行为,可以通过重写 ArrangeOverride 和MeasureOverride 方法创建新的布局。 有关自定义布局行为的详细信息,请参阅自定义 Panel 元素。
所有 Panel 元素都支持 FrameworkElement 定义的基本大小调整和定位属性,包括 Height、WidthHorizontalAlignment、VerticalAlignment、Margin 和 LayoutTransform。有关FrameworkElement 定义的定位属性的其他信息,请参阅对齐、边距和填充概述,
Panel 公开对了解和使用布局至关重要的其他属性。 Background 属性用于借助 Brush 填充派生面板元素的边界之间的区域。Children 表示组成 Panel 的子元素集合。 InternalChildren 表示 Children 集合的内容以及由数据绑定生成的成员。两者均由父 Panel 内承载的子元素的 UlElementCollection 组成。
Panel 还定义 OnRender 方法,该方法可用于重写 Panel 的默认呈现行为。
重点:
Panel提供了GetZIndex和SetzIndex方法成员,分别表示获取某个元素的ZIndex顺序和设置某个元素的ZIndex顺序。
什么是ZIndex?这是Panel提供的一个附加属性 。假如一个单行单列的Grid布局控件中有两个Button,正常情况下,这两个Button都会以撑满Grid的方式呈现在Grid中,那么,到底哪一个Button在上面,哪一个Button在下面呢?就看这两个Button的Panel.Zindex附加属性的值,值越大越在上面,而值较小的那个Button将被上面的Button遮盖,从而在视觉上,用户只能看到一个Button。
<Button Panel.ZIndex="1” Content="按钮1” Width="200"/>
<Button Panel.ZIndex="0" Content="按钮2” Width=”200"/>
Grid网格
Grid 是 WPF 中最强大、最常用的布局容器之一,它以行和列的形式组织子元素,类似于 HTML 表格。
特点:
-
网格结构:通过行(Row)和列(Column)定义布局
-
灵活尺寸:支持固定、自动(auto)和比例(*)分配三种尺寸模式
-
单元格合并:允许元素跨越多行多列
-
精准定位:可以精确控制元素在网格中的位置
<Grid>
<!-- 定义4列 -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/> //根据内容自动调整大小
<ColumnDefinition Width="*"/> //按比例分配尺寸
<ColumnDefinition Width="2*"/> //按比例分配尺寸,如2*
表示占用其他*
定义的两倍空间
<ColumnDefinition Width="100"/> //使用固定像素值定义尺寸
</Grid.ColumnDefinitions>
<!-- 定义3行 -->
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<!-- 子元素 -->
<Button Grid.Column="0" Grid.Row="0" Content="按钮1"/>
<TextBox Grid.Column="1" Grid.Row="0" Grid.ColumnSpan="2"/>
</Grid>
行列属性:
常用附加属性
-
Grid.Row
- 指定元素所在行(从0开始) -
Grid.Column
- 指定元素所在列(从0开始) -
Grid.RowSpan
- 元素跨越的行数 -
Grid.ColumnSpan
- 元素跨越的列数
<!-- 跨越两列 -->
<Button Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Content="跨列按钮"/><!-- 跨越两行 -->
<Label Grid.Row="0" Grid.Column="2" Grid.RowSpan="2" Content="跨行标签"/>
网格线辅助功能
显示网格线:
<Grid ShowGridLines="True">
<!-- 行列定义 -->
</Grid>
使用技巧
-
命名行列:为复杂布局的行列添加x:Name便于维护
-
Margin属性:为子元素设置Margin增加间距
-
结合其他布局:Grid内可以嵌套StackPanel等其他布局容器
-
设计时辅助:使用Visual Studio的设计器拖拽创建Grid布局
示例样子:
UniformGrid(均分布局)
UniformGrid 是 Grid 的一个简化版本,它提供了一种快速创建均匀分布的网格布局的方式。
特点:
-
自动均分:所有单元格大小相同
-
自动排列:子元素按顺序自动填充单元格
-
简化配置:无需定义行和列,只需指定行列数
-
适合场景:需要等分布局的按钮组、图片缩略图等
语法结构:
<UniformGrid Rows="2" Columns="4">
<!-- 子元素将自动均匀排列 -->
<Button Content="按钮1"/>
<Button Content="按钮2"/>
<Button Content="按钮3"/>
</UniformGrid>
属性:
属性 | 说明 | 示例 |
---|---|---|
Rows | 指定行数 | Rows="2" |
Columns | 指定列数 | Columns="3" |
FirstColumn | 第一行起始列索引 | FirstColumn="1" |
HorizontalAlignment | 水平对齐方式 | HorizontalAlignment="Center" |
VerticalAlignment | 垂直对齐方式 | VerticalAlignment="Bottom" |
示例样子:
StackPanel(堆积面板)
StackPanel 是 WPF 中最简单的布局容器之一,它将子元素按单一方向(水平或垂直)依次排列。
特点:
-
线性排列:所有子元素沿一个方向排列
-
自动尺寸:默认根据内容自动调整大小
-
简单轻量:性能优于复杂布局容器
-
适用场景:工具栏、简单列表、表单项分组等
语法:
<!-- 默认垂直排列 -->
<StackPanel>
<Button Content="按钮1"/>
<Button Content="按钮2"/>
<Button Content="按钮3"/>
</StackPanel><!-- 水平排列 -->
<StackPanel Orientation="Horizontal">
<Button Content="确定"/>
<Button Content="取消"/>
<Button Content="帮助"/>
</StackPanel>
属性:
属性 | 说明 | 示例值 |
---|---|---|
Orientation | 排列方向 | Vertical (默认), Horizontal |
Margin | 外边距 | Margin="10" |
Spacing (WPF 4.0+) | 子元素间距 | Spacing="5" |
HorizontalAlignment | 水平对齐 | Center , Left , Right , Stretch |
VerticalAlignment | 垂直对齐 | Top , Center , Bottom , Stretch |
示例样子:
或:
WrapPanel(换行面板)
WrapPanel 是一种流式布局容器,当子元素在主轴方向排列到边界时会自动换行/换列。
特点:
-
自动换行:子元素排满后自动换行/列
-
流式布局:类似网页的流式布局效果
-
灵活排列:支持水平和垂直两个方向的排列
-
适用场景:标签页、图片墙、工具栏按钮组等
语法:
<!-- 默认水平排列,自动换行 -->
<WrapPanel>
<Button Content="按钮1" Width="80"/>
<Button Content="按钮2" Width="80"/>
<!-- 更多按钮... -->
</WrapPanel><!-- 垂直排列,自动换列 -->
<WrapPanel Orientation="Vertical">
<Button Content="按钮A" Height="40"/>
<Button Content="按钮B" Height="40"/>
<!-- 更多按钮... -->
</WrapPanel>
属性:
属性 | 说明 | 示例值 |
---|---|---|
Orientation | 排列方向 | Horizontal (默认), Vertical |
ItemWidth | 统一子项宽度 | ItemWidth="100" |
ItemHeight | 统一子项高度 | ItemHeight="40" |
FlowDirection | 流动方向 | LeftToRight (默认), RightToLeft |
HorizontalAlignment | 水平对齐 | Center , Left , Right , Stretch |
VerticalAlignment | 垂直对齐 | Top , Center , Bottom , Stretch |
与其它布局容器的比较
特性 | WrapPanel | StackPanel | UniformGrid |
---|---|---|---|
排列方式 | 自动换行 | 单方向线性 | 固定行列均分 |
子元素尺寸 | 可自由 | 可自由 | 统一相同 |
适用场景 | 流式布局 | 简单列表 | 严格均分布局 |
示例样子:
DockPanel(停靠面板)
DockPanel 是一种允许子元素停靠在容器边缘或填充剩余空间的布局容器,类似于Windows窗口的停靠行为。
核心特点:
-
边缘停靠:子元素可以停靠在上、下、左、右四个边缘
-
填充剩余:最后一个子元素默认填充剩余空间
-
灵活组合:可以创建复杂的边框式布局
-
适用场景:窗口框架布局、工具栏/状态栏布局、文档编辑器等
一般如图所示(实际应用可以做调整):
语法:
<DockPanel LastChildFill="True">
<!-- 顶部工具栏 -->
<ToolBar DockPanel.Dock="Top">
<Button Content="文件"/>
<Button Content="编辑"/>
</ToolBar>
<!-- 左侧导航 -->
<TreeView DockPanel.Dock="Left" Width="150"/>
<!-- 底部状态栏 -->
<StatusBar DockPanel.Dock="Bottom">
<StatusBarItem Content="就绪"/>
</StatusBar>
<!-- 填充剩余区域(默认) -->
<RichTextBox/>
</DockPanel>
属性:
属性 | 说明 | 示例值 |
---|---|---|
LastChildFill | 最后一个子元素是否填充剩余空间 | True (默认), False |
DockPanel.Dock (附加属性) | 子元素的停靠位置 | Top , Bottom , Left , Right |
Canvas( 画布)
Canvas 是 WPF 中最基础的布局容器,它允许通过精确的坐标定位子元素,类似于绘图画布的概念。(相当于自己自定义整个布局)
特点:
-
绝对定位:子元素通过坐标精确定位
-
自由重叠:元素可以自由重叠,通过Z轴控制层级
-
无自动布局:不会自动调整子元素位置或大小
-
适用场景:绘图应用、游戏界面、自定义图表、需要精确定位的场景
语法:
<Canvas>
<!-- 使用附加属性定位 -->
<Rectangle Canvas.Left="50" Canvas.Top="30"
Width="100" Height="60" Fill="Blue"/>
<Ellipse Canvas.Left="80" Canvas.Top="50"
Width="120" Height="120" Fill="Red"/>
</Canvas>
属性:
属性 | 说明 | 示例 |
---|---|---|
Canvas.Left | 元素左边缘与画布左边缘的距离 | Canvas.Left="20" |
Canvas.Top | 元素顶部与画布顶部的距离 | Canvas.Top="40" |
Canvas.Right | 元素右边缘与画布右边缘的距离 | Canvas.Right="30" |
Canvas.Bottom | 元素底部与画布底部的距离 | Canvas.Bottom="50" |
Canvas.ZIndex | 控制重叠元素的显示顺序(越大越靠前) | Canvas.ZIndex="1" |
注意:Left/Top 优先级高于 Right/Bottom
Boder(边框控件)
Border 是 WPF 中一个简单但功能强大的布局容器,用于为其他元素添加边框、背景和圆角效果。
特点:
-
边框装饰:可设置边框粗细、颜色和圆角
-
背景填充:支持纯色、渐变或图像背景
-
单一子元素:只能包含一个子元素(可通过布局容器包含多个)
-
适用场景:元素分组、卡片式设计、视觉突出显示等
基本用法:
<Border BorderBrush="Black" BorderThickness="1" CornerRadius="5">
<!-- 只能有一个子元素 -->
<StackPanel>
<TextBlock Text="标题" FontSize="16"/>
<TextBlock Text="内容区域"/>
</StackPanel>
</Border>
属性:
1.边框属性
BorderBrush
:边框颜色
<Border BorderBrush="Red"/>
<Border BorderBrush="#FF00AAFF"/> <!-- 使用十六进制颜色 -->
<Border BorderBrush="{StaticResource MyBrush}"/> <!-- 使用资源 -->
BorderThickness
:边框粗细
<Border BorderThickness="1"/> <!-- 统一粗细 -->
<Border BorderThickness="2,1,2,1"/> <!-- 左,上,右,下 -->
2.背景属性
Background
:背景填充
<Border Background="LightBlue"/>
<Border Background="{StaticResource GradientBrush}"/>
3.圆角效果
CornerRadius
:圆角半径
<Border CornerRadius="5"/> <!-- 统一圆角 -->
<Border CornerRadius="10,5,10,5"/> <!-- 左上,右上,右下,左下 -->
GridSplitter分割窗口控件
GridSplitter 是 WPF 中用于调整 Grid 布局(只能用于Grid布局)行列尺寸的交互式分割器,允许用户在运行时拖动改变相邻行或列的大小。
核心特点:
-
动态调整:用户可通过拖动改变行列尺寸
-
灵活方向:支持水平和垂直分割
-
视觉反馈:拖动时显示实时预览
-
适用场景:可调整大小的面板、分隔窗口、IDE布局等
基本语法结构:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/> <!-- Splitter所在列 -->
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<!-- 左侧内容 -->
<TextBlock Grid.Column="0" Text="左侧面板"/>
<!-- 分割线 -->
<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch"/>
<!-- 右侧内容 -->
<TextBlock Grid.Column="2" Text="右侧面板"/>
</Grid>
主要属性:
属性 | 说明 | 示例值 |
---|---|---|
ResizeDirection | 调整方向 | Auto , Columns , Rows |
ResizeBehavior | 调整行为 | BasedOnAlignment , CurrentAndNext , PreviousAndCurrent , PreviousAndNext |
ShowsPreview | 是否显示拖动预览 | True , False (默认) |
DragIncrement | 最小拖动增量 | DragIncrement="1" |
KeyboardIncrement | 键盘调整增量 | KeyboardIncrement="10" |
内容控件
control类
Control
类是 WPF 中大多数用户界面元素的基类,位于 System.Windows.Controls
命名空间中。它是构建交互式 WPF 应用程序的基础。这些元素使用 ControlTemplate 来定义其外观。
Control是许多控件的基类。比如最常见的按钮(Button)、单选(RadioButton)、复选(CheckBox)、文本框(TextBox)、ListBox、DataGrid、日期控件等等。这些控件通常用于展示程序的数据或获取用户输入的数据,我们可以将这一类型的控件称为内容控件或数据控件,它们与前面的布局控件有一定的区别,布局控件更专注于界面,而内容控件更专注于数据(业务)。
Control类虽然可以实例化,但是在界面上是不会有任何显示的。只有那些继承了Control的子类(控件)才会在界面上显示
特性:
-
可视化呈现:
-
提供基本的可视化外观能力
-
通过
Template
属性支持完全自定义外观
-
-
交互支持:
-
提供基本的用户输入处理(鼠标、键盘等)
-
包含焦点管理功能
-
-
样式支持:
-
支持通过
Style
属性进行样式设置 -
包含
Background
,Foreground
,Font
等常用属性
-
重要成员
成员 | 类型 | 描述 |
---|---|---|
Template | 属性 | 获取或设置控件模板,定义控件的外观 |
Background | 属性 | 获取或设置背景画刷 |
Foreground | 属性 | 获取或设置前景画刷(通常用于文本) |
FontFamily | 属性 | 获取或设置字体家族 |
FontSize | 属性 | 获取或设置字体大小 |
IsEnabled | 属性 | 指示控件是否可用 |
Padding | 属性 | 获取或设置控件内部的填充 |
OnMouseDown | 方法 | 鼠标按下时调用的方法(可重写) |
OnKeyDown | 方法 | 按键按下时调用的方法(可重写) |
Tablndex | 属性 | 获取或设置一个值,确定当用户导航控件通过使用 TAB 键元素接收焦点的顺序。 |
Control 类的双击事件
1. PreviewMouseDoubleClick
事件
-
路由策略: 隧道事件 (Tunneling,从根元素向源元素)
-
触发条件: 当鼠标在控件上双击时
-
事件处理签名:
public event MouseButtonEventHandler PreviewMouseDoubleClick
2. MouseDoubleClick
事件
-
路由策略: 冒泡事件 (Bubbling,从源元素向根元素)
-
触发条件: 当鼠标在控件上双击时
-
事件处理签名:
public event MouseButtonEventHandler MouseDoubleClick
示例代码:
// XAML 中订阅事件
<Button PreviewMouseDoubleClick="Button_PreviewMouseDoubleClick"
MouseDoubleClick="Button_MouseDoubleClick"
Content="双击我"/>// 代码后台
private void Button_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
// 隧道阶段首先触发
Debug.WriteLine("PreviewMouseDoubleClick 事件触发");
// e.Handled = true; // 如果设置为true,将阻止MouseDoubleClick事件触发
}private void Button_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
// 冒泡阶段随后触发
Debug.WriteLine("MouseDoubleClick 事件触发");
}
使用场景建议
-
PreviewMouseDoubleClick
: 当需要提前处理或可能取消双击操作时使用 -
MouseDoubleClick
: 大多数常规双击处理使用此事件
Button按钮
Button 是 WPF 中最基础且最常用的交互控件之一,继承自 ButtonBase
类,而 ButtonBase
又继承自 ContentControl
。
属性 | 类型 | 说明 |
---|---|---|
Content | object | 按钮显示的内容(可以是文本、图像或复杂UI元素) |
IsDefault | bool | 设置为true时,按Enter键会触发此按钮(默认按钮) |
IsCancel | bool | 设置为true时,按Esc键会触发此按钮(取消按钮) |
ClickMode | ClickMode | 指定何时触发Click事件(Press/Release/Hover) |
事件 | 说明 |
---|---|
Click | 按钮被点击时触发(主要事件) |
PreviewMouseDoubleClick | 鼠标双击前触发(继承自Control) |
MouseDoubleClick | 鼠标双击时触发(继承自Control) |
代码示例:
<Button Content="普通按钮" Click="Button_Click"/>
<!-- 带样式的按钮 -->
<Button Content="带样式按钮" Background="LightBlue" Foreground="DarkBlue"
FontWeight="Bold" Padding="10,5"/><!-- 带图标的按钮 -->
<Button>
<StackPanel Orientation="Horizontal">
<Image Source="/icons/save.png" Width="16" Height="16"/>
<TextBlock Text="保存" Margin="5,0,0,0"/>
</StackPanel>
</Button>
CheckBox复选框
CheckBox(复选框)是 WPF 中常用的选择控件,继承自 ToggleButton
,允许用户在两种或三种状态之间进行选择。
属性
属性 | 类型 | 说明 |
---|---|---|
IsChecked | bool? | 复选框状态(true-选中,false-未选中,null-不确定) |
IsThreeState | bool | 是否允许三种状态(true/false/null) |
Content | object | 复选框旁边显示的内容 |
ContentTemplate | DataTemplate | 定义内容呈现方式 |
事件
事件 | 说明 |
---|---|
Checked | 当状态变为选中时触发 |
Unchecked | 当状态变为未选中时触发 |
Indeterminate | 当状态变为不确定时触发 |
Click | 用户点击时触发(继承自ButtonBase) |
RadioButton单选框
RadioButton(单选按钮)是 WPF 中用于实现多选一功能的控件,继承自 ToggleButton
,通常用于一组互斥的选项。
属性:
属性 | 类型 | 说明 |
---|---|---|
IsChecked | bool | 是否被选中 |
GroupName | string | 分组名称,相同组名的RadioButton互斥 |
Content | object | 显示的内容(文本、图像或其他元素) |
事件:
事件 | 说明 |
---|---|
Checked | 当被选中时触发 |
Unchecked | 当取消选中时触发 |
Click | 点击时触发(继承自ButtonBase) |
<!-- 简单单选按钮组 -->
<StackPanel>
<RadioButton Content="选项A" IsChecked="True"/>
<RadioButton Content="选项B"/>
<RadioButton Content="选项C"/>
</StackPanel><!-- 显式分组 -->
<StackPanel>
<RadioButton Content="红色" GroupName="ColorGroup"/>
<RadioButton Content="绿色" GroupName="ColorGroup" IsChecked="True"/>
<RadioButton Content="蓝色" GroupName="ColorGroup"/>
</StackPanel><!-- 数据绑定 -->
<RadioButton Content="男性" IsChecked="{Binding Gender, Converter={StaticResource GenderConverter}, ConverterParameter=Male}"/>
<RadioButton Content="女性" IsChecked="{Binding Gender, Converter={StaticResource GenderConverter}, ConverterParameter=Female}"/>
注意:
-
分组行为:同一容器内的RadioButton会自动成为一组,除非指定不同的GroupName
-
初始选择:应确保至少有一个RadioButton的IsChecked="True"(通常)
-
模板定制:可以通过修改ControlTemplate完全自定义外观
-
键盘导航:使用方向键可在同组RadioButton间导航
RepeatButton重复按钮
表示从按下按钮到释放按钮的时间内重复引发其 Click 事件的控件
属性:
属性 | 类型 | 说明 |
---|---|---|
Delay | int | 首次触发前的延迟时间(毫秒),默认 500ms |
Interval | int | 重复触发间隔时间(毫秒),默认 33ms |
Content | object | 按钮显示的内容 |
事件:
事件 | 说明 |
---|---|
Click | 每次触发时都会引发此事件 |
PreviewMouseDown | 鼠标按下时触发(首次按下) |
PreviewMouseUp | 鼠标释放时触发 |
示例代码:
<!-- 简单增减按钮组 -->
<StackPanel Orientation="Horizontal">
<RepeatButton Content="-" Width="30" Click="Decrease_Click"/>
<TextBox Text="{Binding Value}" Width="50" TextAlignment="Center"/>
<RepeatButton Content="+" Width="30" Click="Increase_Click"/>
</StackPanel><!-- 自定义延迟和间隔 -->
<RepeatButton Content="按住我"
Delay="1000"
Interval="100"
Click="RepeatButton_Click"/>
Lable(标签)
Label(标签)是 WPF 中用于显示文本的控件,相比 TextBlock 提供了更多与用户输入控件交互的功能。Label使用的是Content属性而不是Text属性。这是因为Label内部可以放置任意类型的控件而不仅仅是文本。当然这个内容也可以是一个字符串
属性:
属性 | 类型 | 说明 |
---|---|---|
Content | object | 显示的内容(不仅限于文本) |
Target | UIElement | 指定Label关联的控件(用于助记键导航) |
ContentTemplate | DataTemplate | 定义内容如何呈现 |
与 TextBlock 的主要区别
特性 | Label | TextBlock |
---|---|---|
内容类型 | 可接受任意对象 | 主要处理文本 |
助记键支持 | 支持(通过下划线_) | 不支持 |
性能 | 较重 | 更轻量 |
文本换行 | 需要设置模板 | 原生支持 |
<!-- 简单标签 -->
<Label Content="用户名:"/><!-- 带助记键的标签 -->
<Label Content="_Email:" Target="{Binding ElementName=emailTextBox}"/>
<TextBox x:Name="emailTextBox"/><!-- 包含复杂内容的标签 -->
<Label>
<StackPanel Orientation="Horizontal">
<Image Source="/icons/info.png" Width="16"/>
<TextBlock Text="提示信息" Margin="5,0"/>
</StackPanel>
</Label>
注意事项:
-
助记键:使用下划线_定义(如
_Save
显示为S̲ave,按Alt+S触发) -
Target属性:需要正确设置关联控件的
x:Name
-
性能:简单文本显示优先考虑TextBlock
-
内容对齐:通过
HorizontalContentAlignment
和VerticalContentAlignment
控制
TextBlock文字块
TextBlock 是 WPF 中用于显示只读文本的基础控件,相比 Label 更轻量级,支持丰富的文本格式和布局选项。
属性
属性 | 类型 | 说明 |
---|---|---|
Text | string | 显示的文本内容 |
TextWrapping | TextWrapping | 文本换行方式 (NoWrap/Wrap/WrapWithOverflow) |
TextTrimming | TextTrimming | 文本截断方式 (None/CharacterEllipsis/WordEllipsis) |
TextAlignment | TextAlignment | 文本对齐方式 (Left/Center/Right/Justify) |
LineHeight | double | 行高 |
Font 系列 | 字体相关属性 (FontFamily/FontSize/FontWeight等) |
示例代码:
<!-- 简单文本 -->
<TextBlock Text="Hello, WPF!"/><!-- 多行文本 -->
<TextBlock Text="这是第一行
这是第二行" TextWrapping="Wrap"/><!-- 数据绑定 -->
<TextBlock Text="{Binding UserName}"/><!-- 带格式文本 -->
<TextBlock>
<Run Text="普通文本 "/>
<Bold>粗体文本</Bold>
<LineBreak/>
<Italic>斜体文本</Italic>
<Underline>下划线</Underline>
</TextBlock>
高级用法:
<TextBlock>
<Span FontSize="14">
<Bold>标题:</Bold>
<Run Foreground="Blue">蓝色文本</Run>
<LineBreak/>
<Italic FontFamily="Arial">Arial斜体</Italic>
</Span>
<Hyperlink NavigateUri="https://example.com">超链接</Hyperlink>
</TextBlock>
<Run>
vs <Span>
对比
特性 | <Run> | <Span> |
---|---|---|
主要用途 | 承载文本内容 | 文本容器(可嵌套其他内联元素) |
直接文本支持 | 通过 Text 属性 | 只能包含其他内联元素 |
数据绑定 | 支持:<Run Text="{Binding...}"/> | 不支持直接绑定 |
子元素 | 不能包含其他内联元素 | 可以包含其他内联元素 |
TextBox文本框
TextBox 是 WPF 中最常用的文本输入控件,支持单行和多行文本编辑,提供了丰富的文本处理功能。几乎所有的文本、数字、符号的输入都是用TextBox文本框来完成的。TextBox一般用来获取用户的键盘输入的信息
属性
属性 | 类型 | 说明 |
---|---|---|
Text | string | 获取或设置文本框中的文本内容 |
TextWrapping | TextWrapping | 文本换行方式 (NoWrap/Wrap/WrapWithOverflow) |
MaxLength | int | 允许输入的最大字符数 |
IsReadOnly | bool | 是否为只读模式 |
AcceptsReturn | bool | 是否接受回车键(启用多行) |
AcceptsTab | bool | 是否接受Tab键 |
CaretIndex | int | 获取或设置插入符号位置 |
Selection | 选择文本相关 (SelectionStart/SelectionLength/SelectedText) | |
VerticalScrollBarVisibility | 垂直滚动条是否显示 | |
HorizontalScrollBarVisibility | 水平滚动条是否显示 |
事件
事件 | 说明 |
---|---|
TextChanged | 文本内容变化时触发 |
PreviewTextInput | 文本输入前触发(可拦截输入) |
LostFocus | 失去焦点时触发 |
KeyDown | 当用户在 TextBox 中按下键盘上的任意键时触发 |
KeyUp | 当用户在 TextBox 中释放键盘上的任意键时触发 |
示例代码:
<!-- 单行文本框 -->
<TextBox Text="{Binding UserName}" MaxLength="50"/><!-- 多行文本框 -->
<TextBox Text="{Binding Description}"
AcceptsReturn="True"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto"
Height="100"/><!-- 带水印提示的文本框 -->
<TextBox>
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Foreground" Value="Black"/>
<Style.Triggers>
<Trigger Property="Text" Value="">
<Setter Property="Foreground" Value="Gray"/>
<Setter Property="Text" Value="请输入内容..."/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
注意事项
-
性能:频繁的TextChanged事件处理可能影响性能,考虑使用延迟或去抖动
-
数据绑定:默认UpdateSourceTrigger=LostFocus,需要显式设置为PropertyChanged实现即时更新
-
多行文本:必须设置AcceptsReturn="True"才能输入换行符
-
输入法:对IME输入支持良好,但自定义输入过滤时需特殊处理
PasswordBox密码框
密码框是指出于隐私目的隐藏所键入的字符的文本输入框。 密码框的外观类似文本框,区别在于它在已输入文本的位置呈现占位符。 可配置占位符。
默认情况下,密码框向用户提供了查看其密码的方法,即按下显示按钮。 你可以禁用显示按钮,或提供显示密码的替代机制,如复选框。使用 PasswordBox 控件收集密码或其他隐私数据,如身份证号。
2.密码字符
通过设置 PasswordChar 属性,你可以更改用于屏蔽密码的字符。 此处使用英镑符号替换默认项目符号。
<PasswordBox x:Name="passwordBox" Width="300" PasswordChar=”#”/>
结果如下所示:
2.事件:passworChanged,当密码框里的内容发送了改变,则会触发这个事件。
RichTextBox富文本控件
表示对 FlowDocument 对象进行操作的富文本编辑控件,FlowDocument 是RichTextBox 唯一能
支持子控件。
它比标准的 TextBox 功能更强大,支持格式化文本、段落、图像、超链接等复杂内容。
FlowDocument:是指流文档,一个流文档由一个或多个Block构成,所以它有一个Blocks属性。Block只是一个抽象基类,所以流文档的子元素其实是继承了Block的子类,例如:
- BlockUIContainer(Ul元素容器)
- List(有序列表)
- Paragraph(段落)
- Seation(分组)
- Table(表格)
基本属性:
属性 | 类型 | 说明 |
---|---|---|
Document | FlowDocument | 获取或设置RichTextBox的内容 |
IsReadOnly | bool | 是否为只读模式 |
AcceptsReturn | bool | 是否接受回车键 |
AcceptsTab | bool | 是否接受Tab键 |
Selection | TextSelection | 当前选中的内容 |
常用方法:
方法 | 说明 |
---|---|
SelectAll() | 选择全部内容 |
Cut() /Copy() /Paste() | 剪贴板操作 |
GetSpellingError() | 获取拼写错误 |
基本使用:
<!-- 基本RichTextBox -->
<RichTextBox>
<FlowDocument>
<Paragraph>
<Run FontWeight="Bold">粗体文本</Run>
<LineBreak/>
<Hyperlink NavigateUri="https://example.com">超链接</Hyperlink>
</Paragraph>
</FlowDocument>
</RichTextBox><!-- 带滚动条的RichTextBox -->
<RichTextBox VerticalScrollBarVisibility="Auto" Height="200">
<FlowDocument>
<Paragraph FontSize="14">
<Italic>斜体文本</Italic>
<Span Foreground="Blue">蓝色文本</Span>
</Paragraph>
</FlowDocument>
</RichTextBox>
高级使用:1.动态内容操作,2.文本保存与加载,3. 自定义上下文菜单
我们这里只介绍一下动态内容操作(一下是C#代码):
// 添加格式化文本
var paragraph = new Paragraph();
paragraph.Inlines.Add(new Run("普通文本"));
paragraph.Inlines.Add(new Bold(new Run("粗体文本")));
myRichTextBox.Document.Blocks.Add(paragraph);// 获取选中文本
TextRange selection = new TextRange(
myRichTextBox.Selection.Start,
myRichTextBox.Selection.End);
string selectedText = selection.Text;
ToolTip控件(提示工具)
ToolTip(工具提示)是 WPF 中用于显示额外信息的弹出控件,当用户将鼠标悬停在元素上时显示。
示例样子:
基本属性:
属性 | 类型 | 说明 |
---|---|---|
Content | object | 提示内容(可以是任意元素) |
Placement | PlacementMode | 提示框位置(Bottom/Right/Left/Top等) |
IsOpen | bool | 控制提示框是否显示 |
ShowDuration | int | 显示持续时间(毫秒) |
InitialShowDelay | int | 初始显示延迟(毫秒) |
BetweenShowDelay | int | 两次显示间的延迟(毫秒) |
简单案例:
<!-- 简单文本提示 -->
<Button Content="提交" ToolTip="点击提交表单"/><!-- 复杂内容提示 -->
<Button Content="帮助">
<Button.ToolTip>
<ToolTip>
<StackPanel>
<TextBlock Text="帮助中心" FontWeight="Bold"/>
<TextBlock Text="点击获取更多帮助信息"/>
<Image Source="help.png" Width="50"/>
</StackPanel>
</ToolTip>
</Button.ToolTip>
</Button><!-- 使用ToolTipService -->
<Ellipse Fill="Red" Width="30" Height="30"
ToolTipService.ToolTip="红色圆形"
ToolTipService.InitialShowDelay="500"/>
Popup弹出窗口
Popup(弹出窗口)是 WPF 中用于创建浮动窗口的控件,它可以在其他内容上方显示,非常适合实现下拉菜单、提示框、自定义对话框等交互元素。
示例样子:
基本属性
属性 | 类型 | 说明 |
---|---|---|
IsOpen | bool | 控制Popup是否可见(关键属性) |
Placement | PlacementMode | 定位方式(Bottom/Right/Left/Top/Absolute等) |
PlacementTarget | UIElement | 定位参照元素 |
StaysOpen | bool | 是否在失去焦点时自动关闭 |
AllowsTransparency | bool | 是否允许透明背景 |
PopupAnimation | PopupAnimation | 显示动画(None/Fade/Slide/Scroll) |
常用事件
事件 | 说明 |
---|---|
Opened | Popup打开时触发 |
Closed | Popup关闭时触发 |
下拉菜单实现:
<Button x:Name="menuButton" Content="菜单" Click="ToggleMenuPopup"/> <Popup x:Name="menuPopup" PlacementTarget="{Binding ElementName=menuButton}" StaysOpen="False" Placement="Bottom"> <ListBox Width="{Binding ActualWidth, ElementName=menuButton}"> <ListBoxItem Content="新建"/> <ListBoxItem Content="打开"/> <ListBoxItem Content="保存"/> <Separator/> <ListBoxItem Content="退出"/> </ListBox> </Popup>
Image图像控件
表示用于显示图像的控件,这个图像一般就是指我们本地文件存储的照片或来自于网络请求中的照片资源。
lmage类可用于加载以下图像类型:.bmp、.gif、.ico、jpg、.png、wdp 和 tiff。
注意:加载.gif动画图片时,仅显示第一帧。如果要显示gif图片,可以在nuget服务器中下载 "pfÀnimatedcif 组件。
基本属性
属性 | 类型 | 说明 |
---|---|---|
Source | ImageSource | 图像源(BitmapImage/Uri等) |
Stretch | Stretch | 拉伸方式(None/Fill/Uniform/UniformToFill) |
StretchDirection | StretchDirection | 拉伸方向(UpOnly/DownOnly/Both) |