WPF 入门教程(一)
一.wpf入门
1.wpf 简介
WPF(Windows Presentation Foundation)是微软推出的基于Windows的用户界面框架,属于.NET Framework 3.0及更高版本的一部分。它提供了统一的编程模型、语言和框架,实现了界面设计人员与开发人员的分离工作。
核心特点
1.XAML基础:使用可扩展应用程序标记语言(XAML)定义用户界面,实现界面与逻辑代码的分离。 2.矢量图形支持:提供强大的2D/3D图形渲染能力,基于DirectX技术,支持GPU硬件加速。 3.分辨率无关:自动识别显示器分辨率并进行缩放,适应不同显示设备。 4.数据绑定:内置强大的数据绑定机制,支持MVVM模式开发。 5.丰富的媒体支持:集成文档、音频、视频和动画功能。 技术架构
WPF采用基于DirectX的渲染引擎,相比传统的GDI/GDI+技术,提供了更先进的图形处理能力。
开发优势
设计开发分离:设计师可使用Expression Blend等工具设计界面,开发人员专注于业务逻辑。
现代化UI:支持创建媲美Mac程序的视觉效果,如Vista的半透明窗体效果。
跨版本兼容:支持从Windows XP到最新Windows系统的运行。
多语言支持:可使用C#、VB.NET等.NET语言进行开发。
2.与winform对比
1).基础架构差异
技术基础:
- WinForms基于GDI+进行软件渲染,采用传统的Windows消息循环机制。
- WPF基于DirectX进行硬件加速渲染,使用XAML声明式UI设计
设计理念:
- WinForms采用事件驱动模型,强调快速开发
- WPF采用数据驱动模型,支持MVVM模式
2).功能特性对比
| 特性 | WinForms | WPF |
|---|---|---|
| UI设计 | 拖拽控件,像素级布局 | XAML声明式设计,矢量布局 |
| 图形能力 | 基本2D图形 | 支持2D/3D、动画、特效 |
| 数据绑定 | 简单绑定,需手动更新 | 强大双向绑定,自动更新 |
| 分辨率适配 | 固定DPI | 自动高DPI适配 |
| 学习曲线 | 简单易上手 | 较陡峭(XAML+MVVM) |
3).性能表现
启动速度:
WinForms启动更快(依赖项少)
WPF启动较慢(需加载XAML解析器等) 运行时性能:
WinForms:简单UI性能好,复杂图形性能下降
WPF:复杂图形性能优异(硬件加速),简单UI可能有开销
内存占用:
- WinForms内存占用较低
- WPF内存占用较高(维护更多UI状态)
3.wpf项目结构介绍
3.1 核心文件结构
- App.xaml和App.xaml.cs:应用程序入口点,定义全局资源和启动设置,App.xaml.cs包含应用程序启动逻辑和生命周期事件处理。
- MainWindow.xaml和MainWindow.xaml.cs:主窗口的界面布局定义文件(XAML),对应的代码隐藏文件处理窗口逻辑
- Properties文件夹:包含AssemblyInfo.cs(程序集元数据),资源文件(Resources.resx)和设置文件(Settings.settings)。
3.2 常见目录结构
- 资源管理(Resources):存储图片、字体、样式等资源,可细分为Images、Styles、Themes等子目录
- 视图组织(Views):存放应用程序页面(XAML文件)
- 代码分层:数据模型类(Models),MVVM模式中的视图模型(ViewModels),业务逻辑和服务类(Services)
- 用户控件:自定义控件(Controls)/自定义用户控件(UserControls):存放可重用的自定义控件
3.3 生成目录
- bin目录:包含Debug和Release版本的生成输出
- obj目录:包含Debug和Release,存储中间编译结果
3.4 配置文件
- App.config:应用程序配置文件,包含连接字符串等设置
- .csproj:XML格式的项目配置文件,定义项目属性、引用和构建规则
3.5 项目结构示例

4.App.xaml介绍
App.xaml是WPF(Windows Presentation Foundation)应用程序的核心文件,作为应用程序的主入口点和资源管理中心。
基本概念
应用程序入口:App.xaml是WPF应用程序的启动文件,自动加载并解析
代码分离:通常与App.xaml.cs配对使用,后者包含应用程序逻辑代码
全局资源管理:集中管理应用程序级别的资源,如样式、模板和动画 主要功能
资源定义:定义全局样式、模板和数据模板,资源可在整个应用程序中重复使用。
应用程序配置:通过StartupUri属性指定启动窗口,配置应用程序初始设置,如窗口大小、标题等。
生命周期管理:处理应用程序级别事件(启动、退出、异常等),包含OnStartup、OnExit等重写方法
代码结构示例
StartupUri默认值应该为MainWindow.xaml,由于这里移动了MainWindow.xaml到views文件夹下,所以进行了修改
<Application x:Class="TestWpfApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestWpfApp"
StartupUri="./views/MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
using System.Windows;
namespace TestWpfApp
{
/// <summary>
/// App.xaml 的交互逻辑
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
// 启动逻辑
}
}
}
5.Application生命周期
WPF应用程序的生命周期由Application类控制,主要包括启动、运行和关闭三个阶段。
5.1 启动阶段
5.1.1 程序入口
- WPF应用程序从App.xaml文件开始执行,自动生成Main()方法作为程序入口。
- 创建Application实例并初始化。
5.1.2 初始化过程
- 加载App.xaml文件中的配置和资源
- 调用InitializeComponent()方法初始化XAML
- 触发Startup事件(通过OnStartup方法)
5.1.3 主窗口创建
- 根据StartupUri属性创建并显示主窗口
- 或可在OnStartup方法中手动创建窗口
5.2 运行阶段
5.2.1 消息循环
- 调用Application.Run()方法进入消息循环
- 应用程序开始处理用户输入和事件
5.2.2 状态变化
- Activated:当应用程序窗口获得焦点时触发
- Deactivated:当应用程序窗口失去焦点时触发
5.2.3 异常处理
- DispatcherUnhandledException:处理UI线程未捕获的异常
- AppDomain.CurrentDomain.UnhandledException:处理所有线程的未捕获异常
- TaskScheduler.UnobservedTaskException:处理Task异常
5.3 关闭阶段
5.3.1 关闭模式
- OnLastWindowClose:最后一个窗口关闭时退出(默认)
- OnMainWindowClose:主窗口关闭时退出
- OnExplicitShutdown:必须显式调用Shutdown()方法退出
5.3.2 关闭事件
- 触发Exit事件(通过OnExit方法)
- 执行资源清理操作
5.3.3 关闭方法
- Application.Current.Shutdown():优雅关闭
- Environment.Exit(0):强制立即终止
5.4 关键事件顺序
Startup → Activated → (运行期间可能多次触发Activated/Deactivated) → Exit
using System;
using System.Windows;
namespace TestWpfApp
{
/// <summary>
/// App.xaml 的交互逻辑
/// </summary>
public partial class App : Application
{
// 启动
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Console.WriteLine("启动");
}
// 获取焦点
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
Console.WriteLine("获取焦点");
}
// 失去焦点
protected override void OnDeactivated(EventArgs e)
{
base.OnDeactivated(e);
Console.WriteLine("失去焦点");
}
// 关闭
protected override void OnExit(ExitEventArgs e)
{
base.OnExit(e);
Console.WriteLine("关闭");
}
}
}
6.窗体生命周期
6.1 主要生命周期阶段
6.1.1 创建与初始化
1.构造函数调用:通过new Window()实例化窗口对象 2.InitializeComponent():解析XAML并构建可视化树 3.OnInitialized事件:元素初始化完成,数据绑定已准备
6.1.2 加载阶段
1.SourceInitialized:窗口句柄(HWND)已创建,可进行Win32 API调用 2.Loaded事件:窗口布局完成,所有子控件已加载 3.ContentRendered:窗口内容首次完成渲染
6.1.3 激活/停用
1.Activated:窗口获得焦点(首次显示或用户切换回来) 2.Deactivated:窗口失去焦点(用户切换到其他窗口)
6.1.4 关闭阶段
1.Closing:窗口即将关闭,可取消关闭操作(e.Cancel = true) 2.Closed:窗口已关闭,可进行资源清理 3.Unloaded:窗口从可视化树中移除
6.2 关键事件顺序
构造函数 → OnInitialized → SourceInitialized → Loaded → ContentRendered → Activated → (运行时可能多次Activated/Deactivated) → Closing → Closed → Unloaded
6.3 窗口点击关闭时拦截
using System.ComponentModel;
using System.Windows;
namespace TestWpfApp
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
protected override void OnClosing(CancelEventArgs e)
{
base.OnClosing(e);
e.Cancel = MessageBox.Show("确定要关闭吗?", "提示", MessageBoxButton.YesNo) != MessageBoxResult.Yes;
}
}
}
7.窗体结构介绍
7.1 基本组成结构
7.1.1 客户区与非客户区
- 非客户区:包括边框(Border)、标题栏(Title Bar)、图标(Icon)、最大化/最小化/关闭按钮等系统标准元素
- 客户区:开发者自定义内容的工作区域,可放置各种WPF控件
7.1.2 核心类继承
System.Object
↓
System.Windows.Threading.DispatcherObject
↓
System.Windows.DependencyObject
↓
System.Windows.Media.Visual
↓
System.Windows.UIElement
↓
System.Windows.FrameworkElement
↓
System.Windows.Controls.Control
↓
System.Windows.Window
7.2 XAML文件结构
典型窗体XAML文件包含以下关键元素
<Window x:Class="TestWpfApp.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:TestWpfApp"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
</Grid>
</Window>
7.3 后台代码结构
对应XAML的后台代码文件
using System.ComponentModel;
using System.Windows;
namespace TestWpfApp
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
7.4 窗体创建方式
7.4.1 设计时创建
通过Visual Studio添加新项→WPF窗口
7.4.2 运行时创建
// 非模态窗口
var window = new Window1();
window.Show();
// 模态窗口,必须关闭才能回到前一个窗口运行
var dialog = new DialogWindow();
dialog.ShowDialog();
8.窗体常用属性
8.1 外观属性
8.1.1 Title
窗口标题栏显示的文本
8.1.2 Icon
窗口左上角显示的图标
8.1.3 WindowStyle
窗口边框样式,有4种取值
- None:无边框
- SingleBorderWindow:单边框(默认)
- ThreeDBorderWindow:3D边框
- ToolWindow:工具窗口样式
8.1.4 Background
窗口背景颜色或图像
8.1.5 AllowsTransparency
是否允许透明效果(需配合WindowStyle=None)
8.1.6 Opacity
窗口透明度(0.0-1.0)
8.2 大小与位置属性
8.2.1 Width/Height
窗口的宽度和高度
8.2.2 MinWidth/MinHeight
窗口的最小宽度和高度
8.2.3 MaxWidth/MaxHeight
窗口的最大宽度和高度
8.2.4 SizeToContent
窗口如何根据内容自动调整大小
- Manual:手动(默认)
- Width:宽度自适应
- Height:高度自适应
- WidthAndHeight:宽高都自适应
8.2.5 WindowStartupLocation
窗口初始位置
- Manual:手动指定(通过Left/Top属性)
- CenterScreen:屏幕中央
- CenterOwner:父窗口中央
8.2.6 Left/Top
窗口左上角的屏幕坐标
8.3 行为属性
8.3.1 ResizeMode
窗口大小调整模式
- oResize:不可调整
- CanMinimize:仅可最小化
- CanResize:可调整(默认)
- CanResizeWithGrip:可调整并显示调整手柄
8.3.2 WindowState
窗口初始状态
- Normal:正常
- Minimized:最小化
- Maximized:最大化
8.3.3 Topmost
是否置顶显示
8.3.4 ShowInTaskbar
是否在任务栏显示
8.3.5 ShowActivated
首次显示时是否自动激活
8.4 内容与交互属性
8.4.1 FontFamily/FontSize
窗口默认字体设置
8.4.2 Cursor
窗口默认光标样式
8.4.3 IsEnabled
窗口是否可用
8.4.4 IsHitTestVisible
是否响应鼠标事件
9.程序退出的几种方式
9.1 优雅关闭方式
WPF推荐的关闭方式,会触发Application的Shutdown事件,允许执行清理工作
Application.Current.Shutdown();
9.2 窗口关闭方式
关闭当前窗口,默认当所有窗口关闭后程序退出,实际是否退出程序取决于ShutdownMode设置
this.Close();
9.3 强制退出方式
立即终止进程,不会触发任何关闭事件,强制退出
Environment.Exit(0); // 0表示正常退出
最暴力的退出方式,类似任务管理器结束进程
Process.GetCurrentProcess().Kill();
9.4 关闭模式控制
// 在App.xaml中设置
Application.Current.ShutdownMode = ShutdownMode.OnLastWindowClose; // 默认,最后一个窗体关闭后退出程序
// 或
Application.Current.ShutdownMode = ShutdownMode.OnMainWindowClose; // 主窗体关闭后退出程序
//或
Application.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown; // 这需要显式 Shutdown 方法调用来停止应用程序。 否则,应用程序将继续在后台运行。
10.命名空间
10.1 基本命名空间
10.1.1 WPF核心命名空间
默认命名空间,包含所有WPF内置控件(如Button、Grid等)
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
10.1.2 XAML语言命名空间
提供XAML特有功能(如x:Name、x:Class、x:Key等)
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
10.2 自定义命名空间
10.2.1 引用系统类库
xmlns:s="clr-namespace:System;assembly=mscorlib"
10.2.2 引用本地程序集
xmlns:local="clr-namespace:MyApp.Namespace"
10.2.3 引用外部程序集
需要指定程序集名称
xmlns:ext="clr-namespace:External.Namespace;assembly=ExternalLib"
10.3 关键作用
避免命名冲突,通过前缀区分同名类(如local:Button vs x:Button)
二.wpf控件继承树
1.继承树图示

2.介绍
2.1 DispatcherObject
DispatcherObject 是 WPF 中的一个基础类,它为 WPF 对象提供了线程关联性(thread affinity)支持,确保对象只能在创建它的线程(通常是 UI 线程)上被访问。
2.1.1 主要成员
public class DispatcherObject
{
// 获取与此对象关联的 Dispatcher
public Dispatcher Dispatcher { get; }
// 检查当前线程是否可以访问此对象
public bool CheckAccess();
// 验证当前线程是否可以访问此对象,如果不行则抛出异常
public void VerifyAccess();
}
2.1.2 使用场景
验证线程访问权限
if (!someControl.CheckAccess())
{
// 当前线程不是创建控件的线程
someControl.Dispatcher.Invoke(() => {
// 在正确的线程上执行操作
someControl.Content = "Updated";
});
}
else
{
// 可以直接访问
someControl.Content = "Updated";
}
从后台线程更新UI
// 后台线程中,同步UI线程更新
Application.Current.Dispatcher.Invoke(() => {
// 这段代码会在UI线程上执行
textBox.Text = "Updated from background thread";
});
// 后台线程中,异步UI线程更新
Application.Current.Dispatcher.InvokeAsync(() => {
// 这段代码会在UI线程上执行
textBox.Text = "Async updated from background thread";
});
2.2 DependencyObject
DependencyObject 是 WPF 的核心基类之一,它为 WPF 属性系统提供了基础支持,实现了依赖属性(Dependency Properties)和附加属性(Attached Properties)的核心功能。
2.2.1 基本概念
依赖属性系统:
- 提供属性值继承、数据绑定、动画和样式支持
- 比传统 CLR 属性更强大但更复杂
2.2.2 核心功能
依赖属性支持:
public class MyControl : DependencyObject
{
// 注册依赖属性
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register(
"MyProperty",
typeof(string),
typeof(MyControl),
new PropertyMetadata("默认值"));
// CLR包装器
public string MyProperty
{
get { return (string)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
}
附加属性支持:
public static class MyAttachedProperties
{
public static readonly DependencyProperty IsSpecialProperty =
DependencyProperty.RegisterAttached(
"IsSpecial",
typeof(bool),
typeof(MyAttachedProperties),
new PropertyMetadata(false));
public static bool GetIsSpecial(DependencyObject obj)
{
return (bool)obj.GetValue(IsSpecialProperty);
}
public static void SetIsSpecial(DependencyObject obj, bool value)
{
obj.SetValue(IsSpecialProperty, value);
}
}
2.2.3 关键方法
| 方法 | 描述 |
|---|---|
| GetValue(DependencyProperty) | 获取依赖属性的值 |
| SetValue(DependencyProperty, object) | 设置依赖属性的值 |
| ClearValue(DependencyProperty) | 清除本地设置的值,恢复默认值 |
| CoerceValue(DependencyProperty) | 强制重新计算属性值 |
| SetCurrentValue(DependencyProperty, object) | 设置属性值但不改变其绑定 |
2.2.4 属性值优先级
1.动画值(最高优先级) 2.本地值(通过SetValue设置) 3.模板属性 4.样式触发器 5.样式Setter 6.主题样式 7.继承值 8.默认值(最低优先级)
2.2.5 实际应用示例
自定义控件中使用依赖属性:
public class CustomButton : Button
{
public static readonly DependencyProperty CornerRadiusProperty =
DependencyProperty.Register(
"CornerRadius",
typeof(CornerRadius),
typeof(CustomButton),
new PropertyMetadata(new CornerRadius(0)));
public CornerRadius CornerRadius
{
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
}
使用附加属性扩展功能:
// 在XAML中使用
<Button local:MyAttachedProperties.IsSpecial="True" Content="特殊按钮"/>
属性值变更通知:
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(
"Value",
typeof(double),
typeof(RangeControl),
new FrameworkPropertyMetadata(
0.0,
FrameworkPropertyMetadataOptions.AffectsRender,
OnValueChanged));
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (RangeControl)d;
control.UpdateVisualState();
}
2.3 Visual
Visual 类是 WPF 可视化系统的核心基类,位于 System.Windows.Media 命名空间,为所有可视化元素提供基础渲染支持。
2.3.1 基本概念
在可视化树中的角色:
- Visual 是 WPF 可视化树的构建块
- 介于 DependencyObject 和 UIElement 之间
- 提供基础的渲染、变换和命中测试功能
与 FrameworkElement 的关系:
- Visual 是轻量级的渲染基类
- UIElement 继承自 Visual 并添加了布局、输入和事件系统
- FrameworkElement 进一步扩展了 UIElement
2.3.2 核心功能
可视化树操作:
// 获取可视化子元素数量
int childCount = VisualTreeHelper.GetChildrenCount(visual);
// 遍历可视化子元素
for (int i = 0; i < childCount; i++)
{
Visual child = VisualTreeHelper.GetChild(visual, i) as Visual;
// 处理子元素...
}
命中测试(Hit Testing):
// 简单命中测试
bool isHit = VisualTreeHelper.HitTest(visual, point) != null;
// 高级命中测试回调
HitTestResultBehavior HitTestCallback(HitTestResult result)
{
// 处理命中结果
return HitTestResultBehavior.Continue;
}
VisualTreeHelper.HitTest(
visual,
null,
HitTestCallback,
new PointHitTestParameters(point));
变换支持:
// 应用变换
visual.Transform = new RotateTransform(45);
// 获取相对于其他visual的变换
GeneralTransform transform = visual.TransformToVisual(otherVisual);
Point transformedPoint = transform.Transform(new Point(0, 0));
2.3.3 关键成员
| 成员 | 描述 |
|---|---|
| VisualTransform | 获取或设置变换 |
| VisualOpacity | 获取或设置不透明度 |
| VisualClip | 获取或设置裁剪区域 |
| VisualEffect | 获取或设置位图效果 |
| VisualParent | 获取父Visual |
| VisualChildrenCount | 获取子Visual数量 |
2.3.4 实际应用场景
自定义渲染
public class CustomVisual : Visual
{
public CustomVisual()
{
// 必须使用DrawingVisual进行自定义渲染
var drawingVisual = new DrawingVisual();
using (DrawingContext dc = drawingVisual.RenderOpen())
{
dc.DrawRectangle(Brushes.Blue, null, new Rect(0, 0, 100, 100));
}
// 添加到可视化树
this.AddVisualChild(drawingVisual);
}
// 必须重写这些成员
protected override int VisualChildrenCount => 1;
protected override Visual GetVisualChild(int index) => /* 返回子Visual */;
}
2.4 UIElement
UIElement 是 WPF 中构建交互式用户界面的核心基类
- 提供基础输入事件系统
- 实现布局测量和排列的初步结构
- 处理焦点和路由事件
- 支持基本的变换和动画
2.4.1 冒泡事件(Bubbling Events)
工作原理:事件从触发源(如按钮点击)开始,向上冒泡到父级控件,直到根元素(如Window)。
示例:Button.Click事件触发后,依次经过StackPanel → Grid → Window
特点:1.命名无前缀(如MouseDown);2.父控件可统一处理子控件事件(如在Grid中处理所有按钮点击);
中断冒泡:在事件处理中设置e.Handled = true可停止传播。
2.4.2 隧道事件(Tunneling Events)
工作原理:事件从根元素向下隧道传递到触发源,通常用于“预览”或拦截事件
示例:PreviewMouseDown从Window开始,经Grid → StackPanel → Button
特点:命名以Preview前缀(如PreviewKeyDown);允许父控件在事件到达目标前处理或拦截(如禁用特定键盘输入);
中断隧道:在父级事件中设置e.Handled = true可阻止事件到达子控件;
2.5 FrameworkElement
扩展布局属性(Width、Margin)、数据绑定(DataContext)和资源管理。
2.5.1 核心属性
布局属性
| 属性 | 说明 |
|---|---|
| Margin | 元素外边距 |
| HorizontalAlignment | 水平对齐方式 |
| VerticalAlignment | 垂直对齐方式 |
| Width/Height | 显式尺寸设置 |
| MinWidth/MaxWidth | 最小/最大宽度 |
| MinHeight/MaxHeight | 最小/最大高度 |
外观属性
| 属性 | 说明 |
|---|---|
| Style | 样式设置 |
| Template | 控件模板 |
| Resources | 本地资源字典 |
| DataContext | 数据上下文 |
行为属性
|属性 |说明| |-|-| |IsEnabled| 是否启用| |Visibility |可见性控制| |Focusable |能否获取焦点| |ToolTip |工具提示内容|
三.布局控件
1.Panel 布局基类
Panel 是 WPF 中所有布局面板的基类,它定义了容器控件如何排列其子元素的基本行为。
1.1 核心功能
1.子元素集合管理:Panel 维护一个子元素集合 (UIElementCollection) 2.布局系统参与:Panel 参与 WPF 的测量(Measure)和排列(Arrange)过程 3.可视化容器:为子元素提供可视化的容器和呈现表面
1.2 主要成员
属性
| 属性 | 类型 | 说明 |
|---|---|---|
| Children | UIElementCollection | 获取面板的子元素集合 |
| Background | Brush | 获取或设置面板的背景画笔 |
| IsItemsHost | bool | 指示此面板是否为 ItemsControl 生成的项的容器 |
| InternalChildren | UIElementCollection | 获取子元素的内部集合(供派生类使用) |
方法
| 方法 | 说明 |
|---|---|
| MeasureOverride(Size) | 测量面板及其子元素所需的大小 |
| ArrangeOverride(Size) | 排列面板的子元素并确定其最终大小 |
| OnRender(DrawingContext) | 参与呈现操作 |
| CreateUIElementCollection(FrameworkElement) | 创建新的 UIElementCollection |
1.3 布局过程
1.3.1 测量阶段(Measure)
确定子元素所需的大小
- 调用 MeasureOverride 方法
- 面板询问每个子元素它们希望有多大
1.3.2 排列阶段(Arrange)
确定子元素的最终位置和大小
- 调用 ArrangeOverride 方法
- 面板根据测量结果安排子元素的实际位置
1.4 常用派生类
1.Canvas:绝对定位面板 2.StackPanel:线性堆叠面板 3.WrapPanel:自动换行面板 4.DockPanel:停靠面板 5.Grid:表格布局面板 6.UniformGrid:均匀网格面板
Border有类似于布局控件的功能,但不属于布局控件,并不继承于Panel
2.Grid网格
Grid 是一个二维布局系统,由行和列组成,可以精确控制子元素的位置和大小,提供了类似 HTML 表格的灵活布局方式。
2.1 核心特性
1.行列定义:可以定义任意数量的行和列 2.单元格定位:子元素可以放置在特定的单元格中 3.跨行跨列:子元素可以跨越多个行或列 4.尺寸控制:支持多种尺寸定义方式(固定、自动、比例)
2.2 基本用法
<Grid>
<!-- 列定义 -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<!-- 行定义 -->
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<!-- 子元素 -->
<Button Grid.Column="0" Grid.Row="0" Content="按钮1"/>
<Button Grid.Column="1" Grid.Row="1" Content="按钮2"/>
<Button Grid.Column="2" Grid.Row="2" Grid.ColumnSpan="2" Content="跨列按钮"/>
</Grid>
2.3 尺寸定义类型
| 类型 | 语法 | 说明 |
|---|---|---|
| 固定值 | Width="100" | 固定像素值 |
| 自动 | Width="Auto" | 根据内容自动调整 |
| 比例 | Width="*" | 按比例分配剩余空间 |
| 加权比例 | Width="2*" | 权重为2的比例分配 |
2.4 跨行跨列
<Button Grid.Column="1" Grid.Row="1"
Grid.ColumnSpan="2" Grid.RowSpan="2"
Content="跨2列2行的按钮"/>
2.5 行列分隔线
<Grid ShowGridLines="True">
<!-- 行列定义 -->
</Grid>
注意:ShowGridLines 仅用于调试,实际应用中应使用 Border 或样式实现分隔线效果
3.均分布局UniformGrid
UniformGrid(均匀网格)是 WPF 中一个特殊的布局面板,它提供了一种简单的方式来创建所有单元格大小相同的网格布局。
3.1 核心特点
1.均匀分布:所有单元格具有相同的大小 2.自动排列:子元素按照行或列的顺序自动填充 3.简化定义:无需单独定义行和列 4.固定行列:可以指定固定的行数或列数
3.2 基本用法
最简单的 UniformGrid
<UniformGrid>
<Button Content="1"/>
<Button Content="2"/>
<Button Content="3"/>
<Button Content="4"/>
<Button Content="5"/>
<Button Content="6"/>
</UniformGrid>
主要属性
| 属性 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| Rows | int | 设置固定的行数 | 0 (自动计算) |
| Columns | int | 设置固定的列数 | 0 (自动计算) |
| FirstColumn | int | 第一行起始列索引 | 0 |
| IsItemsHost | bool | 是否作为 ItemsControl 的项容器 | false |
3.3 高级用法
固定行列数
<!-- 固定3列,行数自动计算 -->
<UniformGrid Columns="3">
<Button Content="1"/>
<Button Content="2"/>
<!-- 共9个按钮 -->
<Button Content="9"/>
</UniformGrid>
从指定列开始
<!-- 共5个按钮,从第2列开始排列 -->
<UniformGrid Columns="3" FirstColumn="1">
<Button Content="1"/>
<Button Content="2"/>
<Button Content="3"/>
<Button Content="4"/>
<Button Content="5"/>
</UniformGrid>
3.4 与 Grid 的比较
| 特性 | UniformGrid | Grid |
|---|---|---|
| 单元格大小 | 统一 | 可不同 |
| 行列定义 | 自动或简单指定 | 需明确定义 |
| 布局复杂度 | 简单 | 复杂 |
| 适用场景 | 简单均匀布局 | 复杂精确布局 |
| 性能 | 较高 | 较低 |
4.堆积面板StackPanel
以线性方式(水平或垂直)排列其子元素
4.1 特点
1.线性布局:子元素按单一方向(水平或垂直)依次排列 2.自动堆叠:无需指定位置,自动按顺序排列 3.尺寸控制:可以控制子元素的拉伸方式 4.简单高效:布局计算简单,性能较好
4.2 基本用法
4.2.1 垂直堆叠(默认)
<StackPanel>
<Button Content="按钮1"/>
<Button Content="按钮2"/>
<Button Content="按钮3"/>
</StackPanel>
4.2.2 水平堆叠
<StackPanel Orientation="Horizontal">
<Button Content="按钮1"/>
<Button Content="按钮2"/>
<Button Content="按钮3"/>
</StackPanel>
4.3 主要属性
| 属性 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| Orientation | Orientation | 排列方向(Vertical/Horizontal) | Vertical |
| Margin | Thickness | 面板外边距 | 0 |
| Spacing (WPF 4.0+) | double | 子元素之间的间距 | 0 |
4.4 高级用法
4.4.1 子元素对齐控制
<StackPanel>
<!-- 水平方向左对齐 -->
<Button Content="左" HorizontalAlignment="Left" Width="100"/>
<!-- 水平方向居中 -->
<Button Content="中" HorizontalAlignment="Center" Width="100"/>
<!-- 水平方向拉伸 -->
<Button Content="拉伸" HorizontalAlignment="Stretch"/>
</StackPanel>
4.4.2 滚动支持
<ScrollViewer>
<StackPanel>
<!-- 多个子元素 -->
<Button Content="Item 1" Height="50"/>
<!-- ... -->
<Button Content="Item 20" Height="50"/>
</StackPanel>
</ScrollViewer>
4.5 布局行为
4.5.1 测量阶段
- 垂直 StackPanel:宽度取最宽子元素,高度为所有子元素高度之和
- 水平 StackPanel:高度取最高子元素,宽度为所有子元素宽度之和
4.5.2 排列阶段
- 按指定方向依次排列子元素
- 考虑子元素的 Margin 和 Alignment 设置
4.5.3 尺寸分配
- 子元素默认获得其所需尺寸
- 当空间不足时,按比例压缩(基于 DesiredSize)
4.6 简单的工具栏
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Background="LightGray">
<Button Content="新建" Margin="5"/>
<Button Content="打开" Margin="5"/>
<Button Content="保存" Margin="5"/>
<!--分割-->
<Separator Margin="5" Width="2" Background="White"/>
<Button Content="剪切" Margin="5"/>
<Button Content="复制" Margin="5"/>
<Button Content="粘贴" Margin="5"/>
</StackPanel>
</Grid>
5.换行面板WrapPanel
WrapPanel(换行面板)是 WPF 中一个灵活的布局容器,它能够按照指定方向排列子元素,并在空间不足时自动换行或换列。
5.1 特点
1.自动换行:当空间不足时自动换行/换列 2.方向可控:支持水平和垂直两种排列方向 3.流式布局:类似网页中的流式布局效果 4.均匀排列:默认情况下子元素均匀分布
5.2 基本用法
水平排列(默认)
<WrapPanel>
<Button Content="按钮1" Width="100"/>
<Button Content="按钮2" Width="100"/>
<!-- 更多按钮 -->
<Button Content="按钮8" Width="100"/>
</WrapPanel>
垂直排列
<WrapPanel Orientation="Vertical">
<Button Content="按钮1" Height="40"/>
<Button Content="按钮2" Height="40"/>
<!-- 更多按钮 -->
<Button Content="按钮8" Height="40"/>
</WrapPanel>
5.3 主要属性
| 属性 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| Orientation | Orientation | 排列方向(Horizontal/Vertical) | Horizontal |
| ItemWidth | double | 统一设置所有子项宽度 | NaN (自动) |
| ItemHeight | double | 统一设置所有子项高度 | NaN (自动) |
| FlowDirection | FlowDirection | 内容流动方向(LeftToRight/RightToLeft) | LeftToRight |
5.4 统一子项尺寸
<WrapPanel ItemWidth="120" ItemHeight="60">
<Button Content="按钮1"/>
<Button Content="按钮2"/>
<!-- 所有按钮将统一为120x60尺寸 -->
</WrapPanel>
5.5 从右向左排列
<WrapPanel FlowDirection="RightToLeft">
<Button Content="1"/>
<Button Content="2"/>
<!-- 元素将从右向左排列 -->
</WrapPanel>
5.6 与滚动视图结合
<ScrollViewer HorizontalScrollBarVisibility="Auto">
<WrapPanel Width="500">
<!-- 多个子元素 -->
</WrapPanel>
</ScrollViewer>
6.停靠面板DockPanel
6.1 核心特点
1.边缘停靠:子元素可以停靠在上、下、左、右四个边缘 2.填充剩余:最后一个子元素可以填充剩余空间 3.动态调整:当面板大小改变时自动调整布局 4.嵌套支持:可以嵌套使用创建复杂布局
6.2 主要属性
| 属性 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| LastChildFill | bool | 最后一个子元素是否填充剩余空间 | True |
| DockPanel.Dock | Dock | 子元素的停靠位置(附加属性,Left Top Right Bottom | - |
6.3 简单使用
<Window x:Class="TestWpfApp.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:TestWpfApp"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<DockPanel>
<Grid DockPanel.Dock="Top" Height="60" Background="#ccc"></Grid>
<Grid DockPanel.Dock="Bottom" Height="100" Background="#c1c1c1"></Grid>
<Grid DockPanel.Dock="Left" Width="100" Background="#ddd"></Grid>
<Grid DockPanel.Dock="Right" Width="100" Background="#ddd"></Grid>
<Grid></Grid>
</DockPanel>
</Window>

7.画布Canvas
一种采用绝对定位的方式来排列子元素的布局控件,常配合图形控件使用。
7.1 核心特性
1.绝对定位:子元素通过明确的坐标位置放置 2.自由重叠:元素可以自由重叠,通过Z轴控制层次 3.无自动布局:不会自动调整子元素位置或大小 4.高性能:布局计算简单,性能较高
7.2 基本用法
<Window x:Class="TestWpfApp.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:TestWpfApp"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Canvas>
<Button Width="180" Height="180" Background="Red" Canvas.Left="20" Canvas.Top="20" Panel.ZIndex="5"/>
<Button Width="180" Height="180" Background="Blue" Canvas.Left="50" Canvas.Top="50"/>
<Button Width="180" Height="180" Background="Yellow" Canvas.Left="80" Canvas.Top="80"/>
<Button Width="180" Height="180" Background="Green" Canvas.Bottom="80" Canvas.Right="80"/>
</Canvas>
</Window>

7.3 定位属性
| 附加属性 | 说明 | 示例 |
|---|---|---|
| Canvas.Left | 元素左边缘与Canvas左边缘的距离 | Canvas.Left="50" |
| Canvas.Top | 元素顶部与Canvas顶部的距离 | Canvas.Top="30" |
| Canvas.Right | 元素右边缘与Canvas右边缘的距离 | Canvas.Right="20" |
| Canvas.Bottom | 元素底部与Canvas底部的距离 | Canvas.Bottom="40" |
| Canvas.ZIndex | 控制元素的Z轴顺序(重叠顺序) | Canvas.ZIndex="1" |
8.Border边框
一个装饰控件,用于为其他元素添加边框、背景和圆角等视觉效果,不继承Panel,不属于布局控件但是具有布局功能。
8.1 基本特性
1.单一子元素容器:只能包含一个子元素 2.装饰效果:可添加边框、背景、圆角等 3.布局影响:通过Padding控制内容间距 4.可视化修饰:不改变子元素本身,只增加视觉层次
8.2 主要属性
| 属性 | 类型 | 说明 | 示例 |
|---|---|---|---|
| BorderBrush | Brush | 边框颜色 | BorderBrush="Black" |
| BorderThickness | Thickness | 边框粗细 | BorderThickness="1" 或 BorderThickness="1,2,3,4" |
| Background | Brush | 背景颜色 | Background="#FFEEEE" |
| CornerRadius | CornerRadius | 圆角大小 | CornerRadius="5" 或 CornerRadius="10,5,10,5" |
| Padding | Thickness | 内容与边框间距 | Padding="10" |
| Effect | Effect | 视觉效果(如阴影) | <Border.Effect><DropShadowEffect/></Border.Effect> |
8.3 使用
基本边框
<Border BorderBrush="SteelBlue" BorderThickness="2" Padding="10" Width="200" Height="80">
<TextBlock Text="这是带边框的文本"/>
</Border>

圆角边框
<Border BorderBrush="DarkSlateGray" BorderThickness="1" Width="200" Height="80"
CornerRadius="8" Background="LightGray" Padding="15">
<Button Content="圆角按钮"/>
</Border>

阴影效果
<Border BorderThickness="1" CornerRadius="5" Padding="10" Width="200" Height="80"
Background="White">
<Border.Effect>
<DropShadowEffect ShadowDepth="3" Opacity="0.5"/>
</Border.Effect>
<TextBlock Text="带阴影的边框" FontSize="16"/>
</Border>
嵌套使用
<Border BorderBrush="Black" BorderThickness="1" Margin="10" Width="200" Height="80">
<Border BorderBrush="Gray" BorderThickness="1" Padding="5" Margin="10">
<TextBlock Text="双层边框效果"/>
</Border>
</Border>
视觉分隔
<StackPanel Width="200" Height="200">
<TextBlock Text="第一部分" Margin="5"/>
<Border BorderBrush="LightGray" BorderThickness="0,1,0,0" Margin="5"/>
<TextBlock Text="第二部分" Margin="5"/>
</StackPanel>
图片边框
<Border BorderBrush="Gold" BorderThickness="3" CornerRadius="3" Width="200" Height="200"
Padding="3" Background="Black">
<Image Source="https://www.diandiandidi.club/assets/favicon2.7203e0d9.png" Stretch="Uniform"/>
</Border>
渐变边框
<Border Padding="1" Width="200" Height="200">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="Blue" Offset="0"/>
<GradientStop Color="Red" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<Border Background="White" Padding="10" BorderThickness="3">
<TextBlock Text="渐变边框效果"/>
</Border>
</Border>
单独边框
BorderThickness="3,2,1,0"(左边框),左3、上2、右1、下0
9.GridSplitter分割窗口
GridSplitter(网格分割器)是 WPF 中用于调整 Grid 行或列尺寸的专业控件,它允许用户在运行时通过拖拽来改变行高或列宽
9.1 基本特点
1.交互式调整:用户可通过鼠标拖拽实时调整行列尺寸 2.方向灵活:支持水平和垂直分割 3.精确控制:可限制调整范围和最小/最大尺寸 4.视觉反馈:拖拽时显示预览线
9.2 关键属性
| 属性 | 类型 | 说明 | 示例 |
|---|---|---|---|
| ResizeDirection | Enum | 调整方向(Auto/Columns/Rows) | ResizeDirection="Columns" |
| ResizeBehavior | Enum | 调整行为(基于位置) | ResizeBehavior="PreviousAndNext" |
| ShowsPreview | bool | 是否显示拖拽预览 | ShowsPreview="True" |
| DragIncrement | double | 最小拖拽增量(像素) | DragIncrement="10" |
| KeyboardIncrement | double | 键盘调整增量(像素) | KeyboardIncrement="20" |
ResizeBehavior :
| 值 | 说明 |
|---|---|
| BasedOnAlignment | 根据对齐方式决定调整哪些列/行(默认) |
| CurrentAndNext | 调整当前和下一列/行 |
| PreviousAndCurrent | 调整前一列/行和当前 |
| PreviousAndNext | 调整前一列/行和下一列/行 |
9.3 基本用法 垂直分割器(调整列宽)
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="5"/> <!-- 分割线位置 -->
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="左侧面板" Background="LightBlue"/>
<!-- 垂直分割器 -->
<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch"
Background="Gray"/>
<TextBlock Grid.Column="2" Text="右侧面板" Background="LightGreen"/>
</Grid>
水平分割器(调整行高)
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="5"/> <!-- 分割线位置 -->
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="顶部面板" Background="LightBlue"/>
<!-- 水平分割器 -->
<GridSplitter Grid.Row="1" Height="5" VerticalAlignment="Stretch"
Background="Gray"/>
<TextBlock Grid.Row="2" Text="底部面板" Background="LightGreen"/>
</Grid>
9.4 限制调整范围
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="100"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="2*" MaxWidth="300"/>
</Grid.ColumnDefinitions>
<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch"
ResizeBehavior="PreviousAndNext"/>
</Grid>