WPF学习笔记03-布局Layout
WPF相对于Winform而言,在WPF中是用不同的容器安排布局。每个容器都有各自的布局逻辑,有的以堆栈方式布置有的以单元格排列元素。这也是WPF中比较有意思的,更容易入门。通过了解WPF布局之后能有个大概的WPF乐趣之处。
1 - 理解WPF中布局
区别于Winform而言,Winform中使用刻板的基于坐标的布局将控件放到正确位置。在WPF中,使用流布局(flow)。能创建与显示分辨率和窗口大小无关的,在不同显示器正确缩放。
1.1 - WPF 布局原则
WPF窗口只能包含单个元素。在窗口放置一个容器,然后在该容器中添加其他元素。
WPF中,需要遵循以下几条重要原则:
- 不应显式设定元素尺寸。
- 不应使用屏幕坐标指定元素位置。
- 布局容器的子元素共享可用空间
- 可嵌套的布局容器
WPF应该遵循这些原则,如果不遵循这些原则,最终将得到不是很适合WPF的并且难以维护的用户界面。
1.2 - 布局过程
包含两个阶段:测量和排列。
测量阶段:容器遍历所有子元素,并询问子元素他们所期望的尺寸。
排列阶段:容器在合适的位置放置子元素。
1.3 - 布局容器
所有WPF布局容器都派生于System.Windows.Controls.Panel抽象类的面板

WPF中提供了大量继承于Panel的类。这些类都位于System.Windows.Controls命名空间中
名 称 |
说 明 |
StackPanel |
在水平或垂直的堆栈中放置元素。通常用于更大、更复杂窗口中的一些小区域。 |
WrapPanel |
在一系列中可换行的行中放置元素 |
DockPanel |
根据元素的整个边界调整元素 |
Grid |
根据不可见的表格在行列中排列元素,也是最灵活最常用的容器之一 |
UniformGrid |
在不可见但是强制所在单元格具有相同尺寸放置元素,不常见 |
Canvas |
使用固定坐标绝对定位元素与Winform相似,没有提供锚定或停靠功能。 |
除了这些容器外,还有几个更专业的面板。如TabPanel面板、ToolbarPanel面板和VirtualizingStackPanel面板、InkCanvas控件等等。
2 - 使用StackPanel面板进行简单布局
StackPanel面板是嘴贱的布局容器之一。在单行或者单列中以堆栈方式放置其子元素。
<Window x:Class="Demo_Layout.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:Demo_Layout" mc:Ignorable="d" Title="MainWindow" Height="150" Width="200"> <StackPanel> <Label Content="这个是StackPanel布局"/> <Button Content="第一个按钮"/> <Button Content="第二个按钮"/> <Button Content="第三个按钮"/> <Button Content="第四个按钮"/> </StackPanel> </Window>
界面如下
默认情况下,StackPanel面板按照自上而下顺序排列元素,使每个元素的高度适合它的内容。在上个Demo中,所有元素都被拉伸到整个程序的宽度,如果加宽从窗口,StackPanel也会变宽,里边对应的元素也会拉伸自身。
Orientation属性:可以使面板水平排列元素
<StackPanel Orientation="Horizontal">
界面如下
根据窗口的当前大小可能导致一些元素不适应、
2.1 - 布局属性
名 称 |
说 明 |
HorizontalAlignment |
水平方向有额外空间时,该属性决定了子元素在布局容器中如何定位,可选有Center Left Right Stretch等属性 |
VerticalAlignment |
垂直方向有额外空间时,该属性决定了子元素在布局容器中如何定位,可选有Center Left Right Stretch等属性 |
Margin |
设置对应边距,顺序分别为左上右下,如果两个的话为左右、上下 |
MinWidth和MinHeight |
设置元素的最小尺寸 |
MaxWidth和MaxHeight |
设置元素的最大尺寸 |
Width和Height |
设置元素的尺寸,宽度和高度,不能超过设置的最大值和最小值 |
所有的属性都从FrameworkElement基类继承而来。所以在WPF窗口中所使用的的所有图形小组件都支持这些属性。
2.2 - 对齐方式
对齐方式可以通过下述代码来实现,对齐方式可以分为Left Right Center Stretch
<StackPanel> <Label HorizontalAlignment="Center" Content="这个是StackPanel布局"/> <Button HorizontalAlignment="Left" Content="第一个按钮"/> <Button HorizontalAlignment="Right" Content="第二个按钮"/> <Button Content="第三个按钮"/> <Button Content="第四个按钮"/> </StackPanel>
界面如下
可以看到第一个元素居中,第二个元素居左,第三个元素居右。
2.3 - 边距(Margin)
当我们设置对应第四个元素的Margin属性时,可以看到对应边距
<Button Margin="10" Content="第三个按钮"/>
上下左右边距分别为10个元素
当设置为10,5时
<Button Margin="10,5" Content="第三个按钮"/>
界面如下
当设置为四个元素时
<Button Margin="20,15,10,5" Content="第三个按钮"/>
界面如下
综上所述,当我们这只对应边距(Margin)时,可以分别设置为1,2,4时分别为:
一个时:上下左右分别为对应间距
两个时:左右为第一个、上下为第二个
四个时:分别为左上右下
2.4 - 最小尺寸、最大尺寸以及显式设置尺寸
最小尺寸设置为100时,最大尺寸设置为150时,代码和界面
<Button MinWidth="100" MaxWidth="150" Content="第四个按钮"/>
最小尺寸为每个按钮的尺寸始终不能小于最小尺寸
最大尺寸为不能超过最大尺寸
如果最小宽度大于容器宽度时,按钮一部分将被裁剪掉。否则不允许按钮比Panel面板更宽
3 - WrapPanel和DockPanel面板
3.1 - WrapPanel 面板
WrapPanel面板以一次一行或者一列方式部署控件。默认情况下,WrapPanel的Orientation属性为Horizontal,控件从左向右进行排列,再在下一行中排列。将其属性设置为Vertical,从而在多个列中放置元素。
代码和界面
<Window x:Class="Demo_Layout.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:Demo_Layout" mc:Ignorable="d" Title="MainWindow" Height="250" Width="400"> <WrapPanel Margin="3"> <Button VerticalAlignment="Top" Content="第一个按钮"/> <Button MinHeight="50" Content="第二个按钮"/> <Button VerticalAlignment="Bottom" Content="第三个按钮"/> <Button Content="第四个按钮"/> <Button VerticalAlignment="Center" Content="第五个按钮"/> </WrapPanel> </Window>
界面如下
WrapPanel是唯一一个不能通过灵活使用Grid面板代替的容器
3.2 - DockPanel面板
DockPanel沿着一条外边缘来拉伸所包含的控件。通过对应的附加属性选择靠边,可将对应属性设置为Left,Right,Top,和Bottom。放在DockPanel面板的每个元素都会自动获取该属性。
代码和界面如下
<Window x:Class="Demo_Layout.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:Demo_Layout" mc:Ignorable="d" Title="MainWindow" Height="250" Width="400"> <DockPanel> <Button DockPanel.Dock="Top" Content="上边按钮"/> <Button DockPanel.Dock="Left" Content="左边按钮"/> <Button DockPanel.Dock="Right" Content="右边按钮"/> <Button DockPanel.Dock="Bottom" Content="下边按钮"/> <Button Content="默认充满的按钮"/> </DockPanel> </Window>
界面如下
如果说对应一个里边包含了多个元素可以分别设置
<Window x:Class="Demo_Layout.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:Demo_Layout" mc:Ignorable="d" Title="MainWindow" Height="250" Width="400"> <DockPanel> <StackPanel DockPanel.Dock="Top"> <Button Content="上边按钮"/> <Button HorizontalAlignment="Left" Content="上边按钮2"/> <Button HorizontalAlignment="Right" Content="上边按钮3"/> </StackPanel> <Button DockPanel.Dock="Left" Content="左边按钮"/> <Button DockPanel.Dock="Right" Content="右边按钮"/> <Button DockPanel.Dock="Bottom" Content="下边按钮"/> <Button Content="默认充满的按钮"/> </DockPanel> </Window>
界面如下
3.3 - 嵌套布局容器
布局容器也是可以嵌套的。如创建一个标准对话框,右下角为确认和返回按钮,并在剩余部分创建对应文字说明。
1 - 创建StackPanel,将亮哥按钮放置一块
2 - 在DockPanel放置StackPanel 并停靠下边
3 - 将DockPanel的LastChildFill设置为True
4 - 设置边距属性,提供一定的空白空间
如下代码
<Window x:Class="Demo_Layout.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:Demo_Layout" mc:Ignorable="d" Title="MainWindow" Height="150" Width="200"> <DockPanel LastChildFill="True"> <Border Margin="10" DockPanel.Dock="Top" BorderBrush="Orange" BorderThickness="2" > <TextBlock TextWrapping="Wrap" Height="80" Text="月明星稀,乌鹊南飞,此非曹孟德之诗乎?"/> </Border> <StackPanel DockPanel.Dock="Bottom" HorizontalAlignment="Right" Orientation="Horizontal"> <Button Padding="3" Content="确认"/> <Button Padding="3" Content="取消"/> </StackPanel> </DockPanel> </Window>
界面如下
3.4 - Grid面板
Grid是WPF中最强大的布局容器。很多使用其他完成的用Grid都可以完成。Grid是可以将面板分为几行几列的网格。Grid虽然不可见但是可以将Grid.ShowGridLines属性设置为True。方便调试。
创建Grid需要设置对应的行列,随后填充对应内容。
<Window x:Class="Demo_Layout.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:Demo_Layout" mc:Ignorable="d" Title="MainWindow" Height="150" Width="200"> <Grid ShowGridLines="True"> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> </Grid> </Window>
界面如下
这是Grid的布局,此时我们可以开始向Grid中填充元素。比如我们向第二行第三列中添加一个显示内容为"点击我"的按钮
<Button Content="点击我" Grid.Column="2" Grid.Row="1"/>
界面如下
调整行和列
Grid面板支持三种设置尺寸的方式:
- 绝对设置尺寸方式 如:Width=“100”
- 自动设置尺寸方式 如:Width=“Auto”
- 按照比例设置尺寸方式 如:Width=“*”
<Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="1.5*"/> <RowDefinition Height="2.5*"/> </Grid.RowDefinitions>
自动设置
<Window x:Class="Demo_Layout.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:Demo_Layout" mc:Ignorable="d" Title="MainWindow" Height="150" Width="200"> <Grid ShowGridLines="True"> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <TextBox Margin="10" Grid.Row="0" Text="这是一个测试的"/> <StackPanel Grid.Row="1" HorizontalAlignment="Right" Orientation="Horizontal"> <Button Margin="10,10,2,10" Padding="3" Content="确 认"/> <Button Margin="2,10,10,10" Padding="3" Content="取 消"/> </StackPanel> </Grid> </Window>
界面如下
3.5 - UniformGrid 和 Canvas面板
3.5.1 - UniformGrid面板
UniformGrid不同于Grid 不需要设置对应行列,设置简单Rows和Columns来设置尺寸即可。
比如:
<Window x:Class="Demo_Layout.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:Demo_Layout" mc:Ignorable="d" Title="MainWindow" Height="150" Width="200"> <UniformGrid Rows="3" Columns="3"> <Button Content="1"/> <Button Content="2"/> <Button Content="3"/> <Button Content="4"/> <Button Content="5"/> <Button Content="6"/> <Button Content="7"/> <Button Content="8"/> <Button Content="9"/> </UniformGrid> </Window>
界面如下
3.5.2 - Canvas 面板
Canvas面板允许使用精确的坐标放置元素。需要设置Canvas.Left和Canvas.Top附加属性,Left属性设置元素左边和Canvas面板左边之间的单位数。从左上角(0,0)开始到右下角分别为X,Y。
如下代码:
<Window x:Class="Demo_Layout.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:Demo_Layout" mc:Ignorable="d" Title="MainWindow" Height="150" Width="240"> <Canvas> <Button Canvas.Left="10" Canvas.Top="10" Content="(10,10)"/> <Button Canvas.Left="40" Canvas.Top="60" Content="(40,60)"/> <Button Canvas.Left="100" Canvas.Top="20" Content="(100,20)"/> <Button Canvas.Left="140" Canvas.Top="90" Content="(140,90)"/> </Canvas> </Window>
界面如下:
按照画布的坐标点布局。
其中Z顺序
<Button Canvas.Left="10" Panel.ZIndex="0" Canvas.Top="10" Content="(10,10)1"/> <Button Canvas.Left="10" Panel.ZIndex="1" Canvas.Top="10" Content="(10,10)2"/>
同样的坐标体系,当ZIndex较大时,才会显示在最顶层。当设置第一个元素的ZIndex为2时,界面显示的名称是“(10,10)1”
3.6 - 布局Demo
行列设置:
<Window x:Class="Demo_Layout.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:Demo_Layout" mc:Ignorable="d" Title="MainWindow" Height="350" Width="300"> <Grid Margin="10,3,10,10"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <!--第一行--> <Label Grid.Row="0" Grid.Column="0" Margin="3" Content="主页:" VerticalAlignment="Center"/> <TextBox Grid.Row="0" Grid.Column="1" Margin="3" Height="Auto" VerticalAlignment="Center"/> <Button Grid.Column="2" Grid.Row="0" Content="选择路径" Margin="3" Padding="2" Height="Auto" VerticalAlignment="Center"/> <!--第二行--> <Label Grid.Row="1" Grid.Column="0" Margin="3" Content="系统设置表:" VerticalAlignment="Center"/> <TextBox Grid.Row="1" Grid.Column="1" Margin="3" Height="Auto" VerticalAlignment="Center"/> <Button Grid.Column="2" Grid.Row="1" Content="选择路径" Margin="3" Padding="2" Height="Auto" VerticalAlignment="Center"/> <!--第三行--> <Label Grid.Row="2" Grid.Column="0" Margin="3" Content="人员信息表:" VerticalAlignment="Center"/> <TextBox Grid.Row="2" Grid.Column="1" Margin="3" Height="Auto" VerticalAlignment="Center"/> <Button Grid.Column="2" Grid.Row="2" Content="选择路径" Margin="3" Padding="2" Height="Auto" VerticalAlignment="Center"/> <!--第四行--> <Label Grid.Row="3" Grid.Column="0" Margin="3" Content="权限信息表:" VerticalAlignment="Center"/> <TextBox Grid.Row="3" Grid.Column="1" Margin="3" Height="Auto" VerticalAlignment="Center"/> <Button Grid.Column="2" Grid.Row="3" Content="选择路径" Margin="3" Padding="2" Height="Auto" VerticalAlignment="Center"/> </Grid> </Window>
界面如下:
Demo2
<Window x:Class="Demo_Layout.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:Demo_Layout" mc:Ignorable="d" Title="MainWindow" Height="350" Width="300"> <Grid Margin="10,3,10,10"> <TabControl> <TabItem Header="第一页"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="7*"/> </Grid.RowDefinitions> <StackPanel Orientation="Horizontal" Grid.Row="0"> <Label Content="住院号:" VerticalAlignment="Center"/> <TextBox Height="Auto" HorizontalAlignment="Center" Width="150" Margin="0,5"/> <Button VerticalAlignment="Center" Content="查 询" Height="Auto" Margin="5,5" Width="50"/> </StackPanel> <DataGrid Grid.Row="1"> <DataGrid.Columns> <DataGridTextColumn Header="住院号" Width="80"/> <DataGridTextColumn Header="姓名" Width="90"/> <DataGridTextColumn Header="是否启用" Width="Auto"/> </DataGrid.Columns> </DataGrid> </Grid> </TabItem> <TabItem Header="第二页"/> </TabControl> </Grid> </Window>
界面
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!