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>

界面

posted @   IceAmos  阅读(606)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示