布局的基本原则:
a. 一个窗口中只能包含一个元素
b . 不应使用坐标设置元素的位置
c. 大多数情况不应显示定义元素尺寸
d. 支持多元素时, 可使用嵌套容器
布局属性:
HorizontalAlignment:用于设置子元素在容器中的水平位置。参数: Center、Left、Right、Stretch
VerticalAlignment:用于设置子元素在容器中的垂直位置。参数: Center、Top、Bottom、Stretch
Margin:用于设置子元素在容器中的边距。
参数: 4个方向的边距(左、上、右、下)
使用: 可以同时设置4个相同边距、也可以单独设置每条边的边距。
Height/Width、MinHeight/MinWidth、MaxHeight/ MaxWidth:
设置元素的基本尺寸、有固定尺寸、最小尺寸、最大尺寸
常用六大基础布局容器:Grid、StackPanel、WrapPanel、DockPanel和UniformGrid
1. Grid网格:可以自定义行和列并通过行列的数量、行高列宽来调整控件的布局,近似HTML代码中的table
Grid为最常用的布局容器, 作为View中的主要组成部分, 负责框架中整体的页面布局。
ShowGridLines: 可以设置行业的边距线的显示。
Grid. RowDefinitions : 可以创建任意行, 进行固定高度与百分比或自适应高度设置。
Grid. ColumnDefinitions: 可以创建任意列, 进行固定宽度与百分或自适应宽度设置。
示例代码:
<Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="auto"/> <ColumnDefinition Width="2*"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="2*"/> <RowDefinition/> </Grid.RowDefinitions> </Grid>
2.StackPanel:栈式面板。可将包含的元素在水平或垂直方向排成一条线,当移除一个元素后,后面的元素会自动向前填充空缺(菜单栏经常用到此布局)。
Orientation: 用于设置StackPanel的元素排列方式。默认以垂直的方式布局。
Horizontal为水平布局, Vertical为垂直布局, 分别设置水平和垂直的效果如下:
<StackPanel Orientation="Horizontal"> <Button Width="40" Height="40" Background="Red"/> <Button Width="40" Height="40" Background="Beige" /> <Button Width="40" Height="40" Background="DarkBlue"/> <Button Width="40" Height="40" Background="Pink"/> <Button Width="40" Height="40" Background="DarkGray" /> </StackPanel>

3. WrapPanel:自动折行面板。内部元素在排满一行后能够自动折行,类似于Html中的流式布局。
与StackPanel类似的功能, 相对于WrapPanel , 具有在有限的容器范围内, 可以自动换行, 或者换列处理。具体则取决于WrapPanel的排列方式 (Orientation )。默认水平布局方向(Horizontal)
下图演示当容器的大小不足够呈现有限的元素时, 针对元素会自动换行/列:
<Grid> <WrapPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center"> <Button Width="40" Height="40" Background="Red"/> <Button Width="40" Height="40" Background="Beige" /> <Button Width="40" Height="40" Background="DarkBlue"/> <Button Width="40" Height="40" Background="Pink"/> <Button Width="40" Height="40" Background="DarkGray" /> </WrapPanel> </Grid>

4. DockPanel:泊靠式面板。内部元素可以选择泊靠的方向(上下左右),类似于Winform中设置控件的Dock属性
包含在DockPanel中的元素, 具备DockPanel.Dock的4个枚举值(Top/Left/Right/Bottom) 用于设置元素的锚定位置 .LastChildFill : 容器中的最后一个元素时, 默认该元素填充DockPanel所有空间, 默认值为True .DockPanel中的元素未显示添加DockPanel.Dock属性时, 系统则会默认为DockPanel.Dock=“Left”
<DockPanel LastChildFill="True" Margin="10"> <Button DockPanel.Dock="Top" Width="40" Height="40" Background="Red"/> <Button DockPanel.Dock="Left“ Width="40" Height="40" Background="Beige" /> <Button DockPanel.Dock="Right" Width="40" Height="40" Background="DarkBlue"/> <Button DockPanel.Dock="Bottom" Width="40" Height="40" Background="Pink"/> </DockPanel>

5. UniformGrid:
与Grid不同的是, 该容器具备Columns/Rows 属性, 通过设置该属性, UniformGrid则具备相应的行与列, 但是设置的Columns/Rows不允许单独的进行容器的大小设置。
位于UniformGrid中的子元素, 按输入顺序排列至容器中, 直至填充容器的所有空间。
未显示指定Columns/Rows, UniformGrid则为子元素动态分配Columns/Rows, 换行与换列的基准主要基于UniformGrid的容器大小 ( 宽度与高度) 。
<UniformGrid Margin="10"> <Button Width="40" Height="40" Background="Red"/> <Button Width="40" Height="40" Background="Beige" /> <Button Width="40" Height="40" Background="DarkBlue"/> <Button Width="40" Height="40" Background="Pink"/> <Button Width="40" Height="40" Background="DarkKhaki"/> <Button Width="40" Height="40" Background="PaleGreen"/> <Button Width="40" Height="40" Background="OliveDrab"/> <Button Width="40" Height="40" Background="Beige" /> <Button Width="40" Height="40" Background="Moccasin"/> </UniformGrid> <!--显示设置Columns --> <UniformGrid Margin="10" Columns="4"> <Button Width="40" Height="40" Background="Red"/> <Button Width="40" Height="40" Background="Beige" /> <Button Width="40" Height="40" Background="DarkBlue"/> <Button Width="40" Height="40" Background="Pink"/> <Button Width="40" Height="40" Background="DarkKhaki"/> <Button Width="40" Height="40" Background="PaleGreen"/> <Button Width="40" Height="40" Background="OliveDrab"/> <Button Width="40" Height="40" Background="Beige" /> <Button Width="40" Height="40" Background="Moccasin"/> </UniformGrid>

6、Canvas:画布。内部元素可以使用以像素为单位的绝对坐标进行定位,类似于Windows Form 的布局方式
Canvas面板是基于坐标的布局容器;Canvas中的子元素的位置是需要显性设定的固定位置,通过Canvas的属性Left/Rigth/Top/Bottom来设置子元素相的位置。可以通过设定Canvas.ZIndex属性值或Panel.ZIndex来调整元素的重叠顺序,值越大的越靠前
<Window x:Class="WPF_Code.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> <Ellipse Fill="Gainsboro" Canvas.Left="25" Canvas.Top="25" Width="200" Height="200" /> <Rectangle Canvas.ZIndex="1" Fill="LightBlue" Canvas.Left="25" Canvas.Top="25" Width="50" Height="50" /> <Rectangle Panel.ZIndex="2" Fill="LightCoral" Canvas.Left="50" Canvas.Top="50" Width="50" Height="50" /> <Rectangle Panel.ZIndex="3" Fill="LightCyan" Canvas.Left="75" Canvas.Top="75" Width="50" Height="50" /> </Canvas> </Window>

总结:
掌握最为常用的最外层布局容器 Grid , StackPanel则为有限的空间内垂直或水平分布元素。
WrapPanel 相对于StackPanel 其自适应空间, 可进行自动 ( 换行/换列)处理, 适用于自适应布局及元素的个数不固定的情况。
DockPanel 具备4个方向的锚定功能, 可适应灵活的非固定的页面布局
2026.2.5勇哥注:
继续测试了一下主要布局容器效果:
你可以一段一段的取消注释进行测试。
代码:
<Window x:Class="mtv.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:mtv" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <Grid ShowGridLines="True"> <Grid.RowDefinitions> <RowDefinition Height="35"/> <RowDefinition Height="*"/> <RowDefinition Height="50"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="auto"/> <ColumnDefinition Width="2*"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Button Content="输入用户名:" Grid.Row="0" Grid.Column="0" Margin="5"/> <TextBlock Text="www.skcircle.com" Grid.Row="0" Grid.Column="1" Margin="5" VerticalAlignment="Center"/> <RichTextBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="3" Margin="5"> <FlowDocument> <Paragraph> 这是一个 <Bold>RichTextBox</Bold>控件, <LineBreak></LineBreak>您可以在这里输入和编辑富文本内容。 </Paragraph> <Paragraph> <Bold>这是粗体文本</Bold>,这是普通文本, <Italic>这是斜体文本</Italic>。 </Paragraph> <Paragraph> 这是另一个段落,包含列表: </Paragraph> <List> <ListItem> <Paragraph>列表项 1</Paragraph> </ListItem> <ListItem> <Paragraph>列表项 2</Paragraph> </ListItem> </List> </FlowDocument> </RichTextBox> <GridSplitter Grid.Row="1" Grid.Column="0" Width="5" HorizontalAlignment="Right" VerticalAlignment="Stretch" Background="Gray"/> <GridSplitter Grid.Row="2" Grid.Column="1" Height="5" HorizontalAlignment="Stretch" VerticalAlignment="Top" Background="Green"/> </Grid> <!--<Grid ShowGridLines="True"> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="*"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="2*"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Button Content="Button 1" Grid.Row="0" Grid.Column="0" Margin="5"/> </Grid>--> <!--<Canvas Background="LightBlue"> <Ellipse Width="100" Height="100" Fill="Yellow" Canvas.Left="300" Canvas.Top="100"/> <Rectangle Width="150" Height="100" Fill="Green" Canvas.Left="100" Canvas.Top="200"/> <Line X1="0" Y1="0" X2="200" Y2="200" Stroke="Red" StrokeThickness="5" Canvas.Left="400" Canvas.Top="50"/> <Button Content="Click Me" Width="100" Height="30" Canvas.Left="50" Canvas.Top="50"/> <Button Content="Click Me Too" Width="100" Height="30" Canvas.Left="200" Canvas.Top="150"/> </Canvas>--> <!--<UniformGrid Rows="3" Columns="3"> <Button Content="Button 1" Margin="5"/> <Button Content="Button 2" Margin="5"/> <Button Content="Button 3" Margin="5"/> <Button Content="Button 4" Margin="5"/> <Button Content="Button 5" Margin="5"/> <Button Content="Button 6" Margin="5"/> <Button Content="Button 7" Margin="5"/> <Button Content="Button 8" Margin="5"/> <Button Content="Button 9" Margin="5"/> </UniformGrid>--> <!--<DockPanel LastChildFill="True" > <StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Background="LightGray" Height="40"> <Button Content="Home" Width="100" Margin="5"/> <Button Content="Settings" Width="100" Margin="5"/> <Button Content="About" Width="100" Margin="5"/> </StackPanel> <Grid> <TextBlock Text="Welcome to the Main Window!" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="24" /> </Grid> </DockPanel>--> <!--<ScrollViewer VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible"> <WrapPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center"> <Button Content="Click Me1" Width="100" Height="30" Margin="0,0,0,0" /> <Button Content="Click Me2" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me3" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me4" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me5" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me6" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me7" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me8" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me9" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me10" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me11" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me12" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me13" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me14" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me15" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me16" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me17" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me18" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me19" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me20" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me21" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me22" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me23" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me24" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me25" Width="100" Height="30" Margin="0,0,0,0"/> </WrapPanel> </ScrollViewer>--> <!--<StackPanel Orientation="Vertical" > <Button Content="Click Me1" Width="100" Height="30" Margin="0,0,0,0" /> <Button Content="Click Me2" Width="100" Height="30" Margin="0,0,0,0"/> <Button Content="Click Me3" Width="100" Height="30" Margin="0,0,0,0"/> </StackPanel>--> </Grid> </Window>
这个例子演示的了拆分条和wpf FlowDocument。
wpf FlowDocument是wpf的增强功能。
<Bold>这种标签是它的专属布局功能标签,并不是xaml或者html的标签。

FlowDocument 可以在以下容器中使用:
- <FlowDocumentScrollViewer> - 滚动显示
- <RichTextBox> - 可编辑文档
- <DocumentViewer> - 分页显示
下面是常见的FlowDocument布局标签:

wpf中的richtextbox中进行排版后,还可以保存为xaml格式,这种纯文本格式就包含了这些FlowDocument标签。
当然它也可以选择保存为rtf格式。
Canvas即是容器也是可以做为画面,可以旋转Shape元素。
但是一般不会使用它来做高性能画图用,你可以理解为它画出的东西,可以当控件来操作,拥有事件、样式、模板。开销比较大。

高性能画图应该使用 Geometry + DrawingContext + DrawingVisual 的组合 ,而不是 Shape 类。
Shape类最慢
Geometry(中等)
DrawingContext + DrawingVisual(最快)
- DrawingContext 命令式绘制,类似 GDI+
- 适合大量图形 (数千个)

DrawingContext 和 DrawingVisual 是 WPF 中高性能图形绘制的两个关键类,它们的关系如下:
核心概念
DrawingVisual(画布)
- 是什么 :一个轻量级的可视化元素
- 继承关系 : Visual → ContainerVisual → DrawingVisual
- 特点 :不是 FrameworkElement ,没有 UI 开销(无事件、样式、模板)
- 作用 :作为容器,存储绘制的内容
DrawingContext(画笔)
- 是什么 :用于在 DrawingVisual 上绘制内容的工具
- 特点 :类似 GDI+ 的 Graphics 对象
- 作用 :提供绘制方法(DrawLine、DrawEllipse、DrawGeometry 等)
- 使用方式 :通过 DrawingVisual.RenderOpen() 获取,使用后必须 Dispose
关系图
DrawingVisual (画布) ↓ RenderOpen() DrawingContext (画笔) ↓ 绘制命令 ↓ Close() DrawingVisual (包含绘制结果)
