WPF 入门教程(一)

19 次查看
# 一.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 项目结构示例
![](https://www.diandiandidi.club:12346/api/note/getImage/10/c5d161b9-7e9b-4bab-ac07-37f9d2637513-.png)

## 4.App.xaml介绍
App.xaml是WPF(Windows Presentation Foundation)应用程序的核心文件,作为应用程序的主入口点和资源管理中心。

**基本概念**

- ​应用程序入口​​:App.xaml是WPF应用程序的启动文件,自动加载并解析
- ​​代码分离​​:通常与App.xaml.cs配对使用,后者包含应用程序逻辑代码
- ​​全局资源管理​​:集中管理应用程序级别的资源,如样式、模板和动画
主要功能

- 资源定义:定义全局样式、模板和数据模板,资源可在整个应用程序中重复使用。
- 应用程序配置​​:通过StartupUri属性指定启动窗口,配置应用程序初始设置,如窗口大小、标题等。
- 生命周期管理​​:处理应用程序级别事件(启动、退出、异常等),包含OnStartup、OnExit等重写方法

代码结构示例

> StartupUri默认值应该为MainWindow.xaml,由于这里移动了MainWindow.xaml到views文件夹下,所以进行了修改


```xml
<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>
```


```c#
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


```c#
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 窗口点击关闭时拦截

```c#
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 ​​核心类继承​​


```language
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文件包含以下关键元素


```xml
<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的后台代码文件


```c#
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 运行时创建

```c#
// 非模态窗口
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事件,允许执行清理工作

```c#
Application.Current.Shutdown();
```

### 9.2 窗口关闭方式
关闭当前窗口,默认当所有窗口关闭后程序退出,实际是否退出程序取决于ShutdownMode设置


```c#
this.Close();
```

### 9.3 强制退出方式
立即终止进程,不会触发任何关闭事件,强制退出

```c#
Environment.Exit(0); // 0表示正常退出
```

最暴力的退出方式,类似任务管理器结束进程


```c#
Process.GetCurrentProcess().Kill();
```

### 9.4 关闭模式控制

```c#
// 在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等)


```language
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
```

#### 10.1.2 XAML语言命名空间

提供XAML特有功能(如x:Name、x:Class、x:Key等)


```language
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
```

### 10.2 自定义命名空间
#### 10.2.1 引用系统类库


```language
xmlns:s="clr-namespace:System;assembly=mscorlib"
```

#### 10.2.2 引用本地程序集


```language
xmlns:local="clr-namespace:MyApp.Namespace"
```

#### 10.2.3 引用外部程序集

需要指定程序集名称


```language
xmlns:ext="clr-namespace:External.Namespace;assembly=ExternalLib"
```

### 10.3 关键作用
避免命名冲突,通过前缀区分同名类(如local:Button vs x:Button)

# 二.wpf控件继承树
## 1.继承树图示
![](https://www.diandiandidi.club:12346/api/note/getImage/10/256a3806-7e78-4306-9647-40a87835b269-.png)
## 2.介绍
### 2.1 DispatcherObject
DispatcherObject 是 WPF 中的一个基础类,它为 WPF 对象提供了线程关联性(thread affinity)支持,确保对象只能在创建它的线程(通常是 UI 线程)上被访问。

#### 2.1.1 主要成员


```c#
public class DispatcherObject
{
    // 获取与此对象关联的 Dispatcher
    public Dispatcher Dispatcher { get; }
    
    // 检查当前线程是否可以访问此对象
    public bool CheckAccess();
    
    // 验证当前线程是否可以访问此对象,如果不行则抛出异常
    public void VerifyAccess();
}
```

#### 2.1.2 使用场景

验证线程访问权限​


```c#
if (!someControl.CheckAccess())
{
    // 当前线程不是创建控件的线程
    someControl.Dispatcher.Invoke(() => {
        // 在正确的线程上执行操作
        someControl.Content = "Updated";
    });
}
else
{
    // 可以直接访问
    someControl.Content = "Updated";
}
```

从后台线程更新UI​


```c#
// 后台线程中,同步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 核心功能
依赖属性支持:


```c#
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); }
    }
}
```

附加属性支持:


```c#
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 实际应用示例
自定义控件中使用依赖属性:


```c#
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); }
    }
}
```

使用附加属性扩展功能:


```c#
// 在XAML中使用
<Button local:MyAttachedProperties.IsSpecial="True" Content="特殊按钮"/>
```

属性值变更通知:


```c#
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 核心功能
可视化树操作:


```c#
// 获取可视化子元素数量
int childCount = VisualTreeHelper.GetChildrenCount(visual);

// 遍历可视化子元素
for (int i = 0; i < childCount; i++)
{
    Visual child = VisualTreeHelper.GetChild(visual, i) as Visual;
    // 处理子元素...
}
```

命中测试(Hit Testing):


```c#
// 简单命中测试
bool isHit = VisualTreeHelper.HitTest(visual, point) != null;

// 高级命中测试回调
HitTestResultBehavior HitTestCallback(HitTestResult result)
{
    // 处理命中结果
    return HitTestResultBehavior.Continue;
}

VisualTreeHelper.HitTest(
    visual, 
    null, 
    HitTestCallback, 
    new PointHitTestParameters(point));
```

变换支持:


```c#
// 应用变换
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 实际应用场景
自定义渲染


```c#
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 基本用法

```xml
<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 跨行跨列

```xml
<Button Grid.Column="1" Grid.Row="1" 
        Grid.ColumnSpan="2" Grid.RowSpan="2"
        Content="跨2列2行的按钮"/>
```

### 2.5 行列分隔线

```xml
<Grid ShowGridLines="True">
    <!-- 行列定义 -->
</Grid>
```

> 注意:ShowGridLines 仅用于调试,实际应用中应使用 Border 或样式实现分隔线效果

## 3.均分布局UniformGrid
UniformGrid(均匀网格)是 WPF 中一个特殊的布局面板,它提供了一种简单的方式来创建所有单元格大小相同的网格布局。

### 3.1 核心特点
1.均匀分布:所有单元格具有相同的大小
2.自动排列:子元素按照行或列的顺序自动填充
3.简化定义:无需单独定义行和列
4.固定行列:可以指定固定的行数或列数


### 3.2 基本用法
最简单的 UniformGrid


```xml
<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 高级用法
固定行列数


```xml
<!-- 固定3列,行数自动计算 -->
<UniformGrid Columns="3">
    <Button Content="1"/>
    <Button Content="2"/>
    <!-- 共9个按钮 -->
    <Button Content="9"/>
</UniformGrid>
```

从指定列开始


```xml
<!-- 共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 垂直堆叠(默认)

```xml
<StackPanel>
    <Button Content="按钮1"/>
    <Button Content="按钮2"/>
    <Button Content="按钮3"/>
</StackPanel>
```

4.2.2 水平堆叠

```xml

<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 子元素对齐控制

```xml
<StackPanel>
    <!-- 水平方向左对齐 -->
    <Button Content="左" HorizontalAlignment="Left" Width="100"/>
    <!-- 水平方向居中 -->
    <Button Content="中" HorizontalAlignment="Center" Width="100"/>
    <!-- 水平方向拉伸 -->
    <Button Content="拉伸" HorizontalAlignment="Stretch"/>
</StackPanel>
```

#### 4.4.2 滚动支持

```xml
<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 简单的工具栏

```xml
<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 基本用法
水平排列(默认)


```xml
<WrapPanel>
    <Button Content="按钮1" Width="100"/>
    <Button Content="按钮2" Width="100"/>
    <!-- 更多按钮 -->
    <Button Content="按钮8" Width="100"/>
</WrapPanel>
```

垂直排列


```xml
<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 统一子项尺寸

```xml
<WrapPanel ItemWidth="120" ItemHeight="60">
    <Button Content="按钮1"/>
    <Button Content="按钮2"/>
    <!-- 所有按钮将统一为120x60尺寸 -->
</WrapPanel>
```

### 5.5 从右向左排列

```xml
<WrapPanel FlowDirection="RightToLeft">
    <Button Content="1"/>
    <Button Content="2"/>
    <!-- 元素将从右向左排列 -->
</WrapPanel>
```

### 5.6 与滚动视图结合

```xml
<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 简单使用

```xml
<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>
```
![](https://www.diandiandidi.club:12346/api/note/getImage/10/a3d41378-9235-419c-8e10-8e15117b7e99-.png)


## 7.画布Canvas
一种采用绝对定位的方式来排列子元素的布局控件,常配合图形控件使用。

### 7.1 核心特性
1.绝对定位:子元素通过明确的坐标位置放置
2.自由重叠:元素可以自由重叠,通过Z轴控制层次
3.无自动布局:不会自动调整子元素位置或大小
4.高性能:布局计算简单,性能较高
### 7.2 基本用法

```xml
<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>
```
![](https://www.diandiandidi.club:12346/api/note/getImage/10/9c2af3bf-e274-4aba-b474-2362501bd552-.png)

### 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 使用
基本边框

```xml
<Border BorderBrush="SteelBlue" BorderThickness="2" Padding="10" Width="200" Height="80">
    <TextBlock Text="这是带边框的文本"/>
</Border>
```

![](https://www.diandiandidi.club:12346/api/note/getImage/10/580b76a3-4a06-4c14-8aff-af4bf7688f78-.png)

圆角边框

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

![](https://www.diandiandidi.club:12346/api/note/getImage/10/3f85c46d-1649-40f0-a929-17a419d0631d-.png)

阴影效果


```xml
<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>
```
![](https://www.diandiandidi.club:12346/api/note/getImage/10/6b8c763b-c6bb-4702-905b-17f19bb90162-.png)
嵌套使用


```xml
<Border BorderBrush="Black" BorderThickness="1" Margin="10" Width="200" Height="80">
    <Border BorderBrush="Gray" BorderThickness="1" Padding="5" Margin="10">
        <TextBlock Text="双层边框效果"/>
    </Border>
</Border>
```
![](https://www.diandiandidi.club:12346/api/note/getImage/10/3ab93857-8001-465a-a4b3-893ee6654dcf-.png)
视觉分隔


```xml
<StackPanel Width="200" Height="200">
    <TextBlock Text="第一部分" Margin="5"/>

    <Border BorderBrush="LightGray" BorderThickness="0,1,0,0" Margin="5"/>

    <TextBlock Text="第二部分" Margin="5"/>
</StackPanel>
```
![](https://www.diandiandidi.club:12346/api/note/getImage/10/12e0818c-8a35-4d3f-96f0-7464864355ea-.png)
图片边框


```xml
 <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>
```
![](https://www.diandiandidi.club:12346/api/note/getImage/10/c4ff44e5-d38d-4456-b168-deccb4ab87a2-.png)
渐变边框


```xml
<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>
```
![](https://www.diandiandidi.club:12346/api/note/getImage/10/62cbd78b-1f4e-4951-9b5b-d1282f741bad-.png)
单独边框
> 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 基本用法
垂直分割器(调整列宽)


```xml
<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>
```

水平分割器(调整行高)


```xml
<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 限制调整范围

```xml
<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>
```





© 2026 XyzRgb.space · 本页内容为个人学习记录,如有错漏欢迎指正。