WPF布局

一、WPF常用的布局控件

控件名称 布局方式
Grid 网格,根据自定义行和列来设置控件的布局
StackPanel 栈式面板,包含的元素在竖直或水平方向排成一条直线
WrapPanel 自动折行面板,包含的元素在排满一行后,自动换行
DockPanel 泊靠式面板,内部的元素可以选择泊靠方向
UniformGrid 网格,UniformGrid就是Grid的简化版,每个单元格的大小相同。
Canvas 画布,内部元素根据像素为单位绝对坐标进行定位
Border 装饰的控件,此控件用于绘制边框及背景,在Border中只能有一个子控件

二、WPF布局原则

 在WPF中,布局由您实用的容器来确定。尽管有多个容器可供选择,但“理想的”WPF窗口需要遵循以下四条条重要原则:

  1. 尽量不要把控件尺寸写死

在 WPF 中,Width 和 Height 不是不能用,但不建议滥用。因为一旦写死,内容变化、字体变化、窗口变化时,就容易出现截断、重叠、空白太大等问题。

更推荐的做法是:

能自动就自动
需要限制范围时,用 MinWidth、MaxWidth
让控件根据内容和容器空间去适应

例如按钮文本变长时,按钮应该自然变宽,而不是把文字挤没。这个思想在原文中被反复强调。

  1. 尽量不要用坐标定位普通界面

普通业务界面中,不建议上来就用 Canvas.Left、Canvas.Top 去摆控件。因为坐标布局虽然“看起来直观”,但适配性差,窗口一变大小就容易乱。

WPF 更提倡:

用 Margin 控制间距
用布局容器控制排列规则
用对齐属性控制位置

所以,大多数表单、后台管理界面、设置页,优先考虑 Grid、StackPanel、DockPanel,而不是 Canvas。这也是原文强调的布局思想。

  1. 让子元素共享空间,而不是各自为战

WPF 容器会根据子元素内容和剩余空间,尽可能把界面安排得合理。尤其是 Grid 中的:

Auto:根据内容自适应
*:占剩余空间
2*:按比例占更多剩余空间

这是 WPF 中非常重要的思维方式。比如左侧导航固定宽度,右侧内容自适应伸缩,这就是典型的 Grid 使用场景。

  1. 学会嵌套布局

现实项目里几乎不可能只靠一个容器打天下。常见做法是:

最外层用 Grid 分区域
局部按钮区用 StackPanel
顶部工具条用 DockPanel
标签流式排列用 WrapPanel

也就是说,布局控件经常是组合使用的。这一点在原文多个示例中也体现得非常明显。

三、布局容器

所有WPF布局容器都是派生自System.Windows.Controls.Panel抽象类的面板。如下图所示:
263728-20200105202958255-944653292

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

263728-20200105235423107-870839500

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

263728-20200105235503903-1783173601

四、stackPanel面板进行布局

StackPanel 适合把控件按一行或一列排列。
垂直排列效果图:Orientation="Vertical"
image
水平排列效果图:Orientation="Horizontal"
image

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、对齐方式

  1. HorizontalAlignment(水平方向对齐)

这个属性决定控件在水平方向上的位置,常见取值有:
Left:靠左
Center:居中
Right:靠右
Stretch:拉伸填满可用宽度

示例图:
image

4.3、边距

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

4.4、最小尺寸、最大尺寸以及显示的尺寸设置

  1. Width / Height:显示指定尺寸
<Button Width="100" Height="30">按钮</Button>
  1. MinWidth / MinHeight:最小尺寸
<Button MinWidth="100">按钮</Button>

意思是:按钮即使内容很短,也不能小于 100。

  1. 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>

image

六、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>

image

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

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>

image

注意点:当停靠控件时,停靠顺序很重要。谁在前面就谁先停靠。

可修改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>

image

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>

效果:
image

七、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>

效果:

image

十、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>

效果:可以让用户直接在界面上写字、画线、涂鸦
image

InkCanvas 和 Canvas 的区别

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