WPF布局
一、WPF常用的布局控件
| 控件名称 | 布局方式 |
|---|---|
| Grid | 网格,根据自定义行和列来设置控件的布局 |
| StackPanel | 栈式面板,包含的元素在竖直或水平方向排成一条直线 |
| WrapPanel | 自动折行面板,包含的元素在排满一行后,自动换行 |
| DockPanel | 泊靠式面板,内部的元素可以选择泊靠方向 |
| UniformGrid | 网格,UniformGrid就是Grid的简化版,每个单元格的大小相同。 |
| Canvas | 画布,内部元素根据像素为单位绝对坐标进行定位 |
| Border | 装饰的控件,此控件用于绘制边框及背景,在Border中只能有一个子控件 |
二、WPF布局原则
在WPF中,布局由您实用的容器来确定。尽管有多个容器可供选择,但“理想的”WPF窗口需要遵循以下四条条重要原则:
- 尽量不要把控件尺寸写死
在 WPF 中,Width 和 Height 不是不能用,但不建议滥用。因为一旦写死,内容变化、字体变化、窗口变化时,就容易出现截断、重叠、空白太大等问题。
更推荐的做法是:
能自动就自动
需要限制范围时,用 MinWidth、MaxWidth
让控件根据内容和容器空间去适应
例如按钮文本变长时,按钮应该自然变宽,而不是把文字挤没。这个思想在原文中被反复强调。
- 尽量不要用坐标定位普通界面
普通业务界面中,不建议上来就用 Canvas.Left、Canvas.Top 去摆控件。因为坐标布局虽然“看起来直观”,但适配性差,窗口一变大小就容易乱。
WPF 更提倡:
用 Margin 控制间距
用布局容器控制排列规则
用对齐属性控制位置
所以,大多数表单、后台管理界面、设置页,优先考虑 Grid、StackPanel、DockPanel,而不是 Canvas。这也是原文强调的布局思想。
- 让子元素共享空间,而不是各自为战
WPF 容器会根据子元素内容和剩余空间,尽可能把界面安排得合理。尤其是 Grid 中的:
Auto:根据内容自适应
*:占剩余空间
2*:按比例占更多剩余空间
这是 WPF 中非常重要的思维方式。比如左侧导航固定宽度,右侧内容自适应伸缩,这就是典型的 Grid 使用场景。
- 学会嵌套布局
现实项目里几乎不可能只靠一个容器打天下。常见做法是:
最外层用 Grid 分区域
局部按钮区用 StackPanel
顶部工具条用 DockPanel
标签流式排列用 WrapPanel
也就是说,布局控件经常是组合使用的。这一点在原文多个示例中也体现得非常明显。
三、布局容器
所有WPF布局容器都是派生自System.Windows.Controls.Panel抽象类的面板。如下图所示:

Panel类添加了少量成员,包括三个公有属性,如下表所示:

就Panel基类本身而言没有什么特别的,但他是其它更多特殊类的起点。WPF提供了大量可用于安排布局的继承自Panel的类。下表列出了其中几个最基本的类。与所有WPF控件和大多数可视化元素一样,这些类位于System.Windows.Controls名称空间里。

四、stackPanel面板进行布局
StackPanel 适合把控件按一行或一列排列。
垂直排列效果图:Orientation="Vertical"

水平排列效果图:Orientation="Horizontal"

4.1、布局属性
| 名称 | 说明 |
|---|---|
| HorizontalAlignment | 当水平方向上有额外的空间时,该属性决定了子元素在布局容器中如何定位。可选用 Center、Left、Right 或 Stretch 等属性值 |
| VerticalAlignment | 当垂直方向上有额外的空间时,该属性决定了子元素在布局容器控件中如何定位。可选用 Center、Top、Bottom 或 Stretch 等属性 |
| Margin | 该属性用于在钴胺素的周围添加一定的空间。Margin 属性是 System.Windows.Thickness 结构的一个实例,该结构具有分别用于为顶部、底部、左边和右边添加空间的独立组件。 |
| MinWidth 和 MinHeight | 这两个属性用于设置元素的最小尺寸。如果一个元素对于其布局容器来说太大,该元素将被剪裁以适合容器。 |
| MaxWidth 和 MaxHeight | 这两个属性用来设置元素的最大尺寸。如果有更多可以使用的空间,那么在扩展子元素时旧不会超出这一限制,即使将 HorizontalAlignment 和 VerticalAlignment 属性设置为 Stretch 也同样如此。 |
| Width 和 Height | 这两个属性用来显示地设置元素的尺寸。这一设置会重写 HorizontalAlignment 和 VerticalAlignment 属性设置的 Stretch 值。但不能超出 MinWidth、MinHeight、MaxWidth 和 MaxHeight 属性设置的范围。 |
4.2、对齐方式
- HorizontalAlignment(水平方向对齐)
这个属性决定控件在水平方向上的位置,常见取值有:
Left:靠左
Center:居中
Right:靠右
Stretch:拉伸填满可用宽度
示例图:

4.3、边距
Margin 用来设置控件与外部之间的距离,也就是“控件和别的控件之间留多大空白”。

4.4、最小尺寸、最大尺寸以及显示的尺寸设置
- Width / Height:显示指定尺寸
<Button Width="100" Height="30">按钮</Button>
- MinWidth / MinHeight:最小尺寸
<Button MinWidth="100">按钮</Button>
意思是:按钮即使内容很短,也不能小于 100。
- MaxWidth / MaxHeight:最大尺寸
<Button MaxWidth="200">按钮</Button>
意思是:按钮再怎么拉伸,也不会超过 200。
4. 推荐做法
<Button Margin="3" MinWidth="100" MaxWidth="200">Button1</Button>
不是直接写死一个绝对宽度。
因为这样既保留了弹性,又能防止控件太小或太大。
五、Border控件(设置边框和背景)
5.1、属性
| 名称 | 说明 |
|---|---|
| Background | 使用 Brush 对象设置边框中所有内容后面的背景。可使用固定颜色背景,也可使用其他更特殊的背景 |
| BorderBrush 和 BorderThickness | 使用 Brush 对象设置位于 Border 对象边缘的边框的颜色,并设置边框的宽度。为显示边框,必须设置这两个属性。(注:原表中 BorerThickn ess 为笔误,应为 BorderThickness) |
| CornerRadius | 该属性可使边框具有雅致的圆角。CornerRadius 的值越大,圆角效果就越明显 |
| Padding | 该属性在边框和内部的内容之间添加空间(与此相对,Margin 属性在边框之外添加空间) |
5.2、示例
<Window x:Class="Layout.BorderWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="BorderWindow" Height="300" Width="300">
<Border Margin="5" Padding="5" Background="LightGoldenrodYellow"
BorderBrush="SteelBlue" BorderThickness="3,5,3,5" CornerRadius="3"
VerticalAlignment="Top">
<StackPanel>
<Button Margin="3">Button1</Button>
<Button Margin="3">Button2</Button>
<Button Margin="3">Button3</Button>
<Button Margin="3">Button4</Button>
</StackPanel>
</Border>
</Window>

六、WrapPanel和DockPanel面板
6.1、WrapPanel面板(自动换行布局)
特点:控件在空间不足时自动换行
示例
<Window x:Class="WrapPanelLayout.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<WrapPanel Margin="5">
<Button VerticalAlignment="Top">Top Button</Button>
<Button MinHeight="60">Tall Button</Button>
<Button VerticalAlignment="Bottom">Bottom Button</Button>
<Button>Stretch Button</Button>
<Button VerticalAlignment="Center">Center Button</Button>
</WrapPanel>
</Window>

当窗口大小进行变化时,有几个按钮被挤到第二行中。因为第二行没有包含特别高的按钮,所以第二行的高度保持最小按钮的高度。因此,在该行中不必关系各按钮的VerticalAlignment属性的设置。

6.2、DockPanel面板(停靠式布局)
DockPanel 常用于顶部、底部、左侧、右侧停靠布局
示例:
<Window x:Class="DockPanelLayout.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<DockPanel LastChildFill="True">
<Button DockPanel.Dock="Top">Top Button</Button>
<Button DockPanel.Dock="Bottom">Bottom Button</Button>
<Button DockPanel.Dock="Left">Left Button</Button>
<Button DockPanel.Dock="Right">Right Button</Button>
<Button>Content Button</Button>
</DockPanel>
</Window>

注意点:当停靠控件时,停靠顺序很重要。谁在前面就谁先停靠。
可修改Margin属性、HorizontalAlignment属性以及VerticalAlignment属性,就像使用StackPanel面板进行布局时所介绍的那样。下面对前面示例进行修改:
<Window x:Class="DockPanelLayout.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<DockPanel LastChildFill="True">
<Button DockPanel.Dock="Top">A Stretched Top Button</Button>
<Button DockPanel.Dock="Top" HorizontalAlignment="Center">A Centered Top Button</Button>
<Button DockPanel.Dock="Top" HorizontalAlignment="Left">A Left-Aligned Top Button</Button>
<Button DockPanel.Dock="Bottom">Bottom Button</Button>
<Button DockPanel.Dock="Left">Left Button</Button>
<Button DockPanel.Dock="Right">Right Button</Button>
<Button>Content Button</Button>
</DockPanel>
</Window>

6.3、嵌套布局
方法:
(1)创建水平StackPanel面板,用于将按钮放置在一起。
(2)在DockPanel面板中放置StackPanel面板,将其停靠到窗口底部。
(3)将DockPanel.LastChildFill属性设置为true,以使用窗口剩余的部分填充其它内容。
(4)设置边距属性,提供一定的空间。
<Window x:Class="DockPanelLayout.CombineLayout"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CombineLayout" Height="300" Width="300">
<DockPanel LastChildFill="True">
<StackPanel DockPanel.Dock="Bottom" HorizontalAlignment="Right" Orientation="Horizontal">
<Button Margin="10,10,2,10" Padding="3">OK</Button>
<Button Margin="2,10,10,10">Cancle</Button>
</StackPanel>
<TextBox DockPanel.Dock="Top" Margin="10">This is test.</TextBox>
</DockPanel>
</Window>
效果:

七、Grid面板
7.1、Grid 核心结构与常用属性
| 名称 | 说明 | 示例 |
|---|---|---|
| Grid | WPF 中最强大的表格型布局容器,可按行和列划分区域,支持子元素跨行 / 跨列。 | |
| Grid.ColumnDefinitions | 定义列集合,每个 ColumnDefinition 代表一列。 | <Grid.ColumnDefinitions> |
| Grid.RowDefinitions | 定义行集合,每个 RowDefinition 代表一行。 | <Grid.RowDefinitions> |
| ColumnDefinition.Width | 列宽,支持三种模式:1. 固定值:1002. 自动:Auto(根据内容宽度)3. 比例:(均分剩余空间)、2(占 2 份) | |
| RowDefinition.Height | 行高,支持三种模式:1. 固定值:1002. 自动:Auto(根据内容高度)3. 比例:(均分剩余空间)、2(占 2 份) | |
| Grid.Column | 子元素的列索引(从 0 开始),表示元素放在哪一列。 | |
| Grid.Row | 子元素的行索引(从 0 开始),表示元素放在哪一行。 | |
| Grid.ColumnSpan | 子元素跨几列,默认值为 1。 | |
| Grid.RowSpan | 子元素跨几行,默认值为 1。 |
7.2、ColumnDefinition / RowDefinition 宽度 / 高度模式对比
| 模式 | 语法 | 说明 | 适用场景 |
|---|---|---|---|
| 固定值 | Width="100" | 列 / 行的尺寸固定为指定像素,不随窗口变化。 | 侧边栏、固定大小的控件 |
| 自动 | Width="Auto" | 列 / 行的尺寸由内容大小决定,刚好包裹内容。 | 标题栏、按钮、自适应内容区域 |
| 比例 | Width="*" | 按比例分配剩余空间。* 表示 1 份,2* 表示 2 份。 | 主内容区、均分的布局 |
7.3、Grid 布局的核心特点与对比
| 特点 | 说明 |
|---|---|
| 行列划分 | 可将容器划分为任意行列数,适合复杂的表格型布局。 |
| 元素跨区 | 支持 RowSpan/ColumnSpan,实现跨行跨列的元素,布局灵活性极高。 |
| 内容对齐 | 每个单元格内的元素可通过 HorizontalAlignment/VerticalAlignment 控制位置。 |
| 与其他容器对比 | 比 StackPanel 更适合多行列布局;比 Canvas 更适合自适应布局;比 WrapPanel 更可控。 |
八、UniformGrid面板(均匀网格布局)
8.1、UniformGrid与Grid的区别
| 特性 | UniformGrid | Grid |
|---|---|---|
| 布局方式 | 所有单元格等宽等高 | 每行/列可以独立定义尺寸 |
| 定义方式 | 只需指定行列数 | 需要逐一定义每行每列的尺寸 |
| 适用场景 | 均匀排列的简单布局(如按钮网格、相册缩略图) | 复杂的不规则布局(如对话框、表单) |
| 灵活性 | 低 | 高 |
| 代码量 | 少 | 多 |
九、Canvas:绝对坐标布局
示例:
<Window x:Class="CanvasLayout.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Canvas>
<Button Canvas.Left="10" Canvas.Top="10">(10,10)</Button>
<Button Canvas.Left="120" Canvas.Top="30">(120,30)</Button>
<Button Canvas.Left="60" Canvas.Top="80" Width="80" Height="60">(60,80)</Button>
<Button Canvas.Left="180" Canvas.Top="150" Width="100" Height="60">(180,150)</Button>
</Canvas>
</Window>
效果:

十、InkCanvas:画笔
示例
<Window x:Class="WpfApp4.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:WpfApp4"
mc:Ignorable="d"
Title="MainWindow" Height="388" Width="496">
<InkCanvas Name="inkCanvas" Background="LightYellow" EditingMode="Ink">
<Image Source="/Images/avatar2.png" Width="300" Height="240" Stretch="Fill" InkCanvas.Top="10" InkCanvas.Left="10"></Image>
</InkCanvas>
</Window>
效果:可以让用户直接在界面上写字、画线、涂鸦

InkCanvas 和 Canvas 的区别
| 对比项 | Canvas | InkCanvas |
|---|---|---|
| 主要作用 | 基础布局容器,用来放控件、自由定位 | 手写板 / 涂鸦板,支持鼠标 / 手写笔绘画、写字 |
| 能否画画 | ❌ 不能 画画、涂鸦 | ✅ 可以 直接用鼠标写字、画线、涂色 |
| 子元素定位 | 使用 Canvas.Top / Canvas.Left | 使用 InkCanvas.Top / InkCanvas.Left |
| 自带功能 | 仅自由布局,无其他功能 | 自带笔迹、橡皮擦、选择、擦除模式 |
| EditingMode | 无此属性 | 有:Ink / Erase / Select / Gesture 等 |
| 保存功能 | 不能保存内容 | 可以将笔迹保存为图片 / 墨迹文件 |
| 用途场景 | 界面自由布局、小游戏界面 | 签名、涂鸦、批注、画图、手写输入 |
| 继承关系 | 直接继承 Panel | 继承自 Canvas,是它的 “加强版” |

浙公网安备 33010602011771号