少有人走的路

勇哥的工业自动化技术网站

WPF 布局控件

布局的基本原则:


    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>

image.png


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>


image.png



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>

 image.png


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>

 

image.png


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>

image.png


总结:


掌握最为常用的最外层布局容器 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的标签。

gif8.gif


FlowDocument 可以在以下容器中使用:

- <FlowDocumentScrollViewer> - 滚动显示

- <RichTextBox> - 可编辑文档

- <DocumentViewer> - 分页显示


下面是常见的FlowDocument布局标签:

image.png


wpf中的richtextbox中进行排版后,还可以保存为xaml格式,这种纯文本格式就包含了这些FlowDocument标签。

当然它也可以选择保存为rtf格式。


Canvas即是容器也是可以做为画面,可以旋转Shape元素。

但是一般不会使用它来做高性能画图用,你可以理解为它画出的东西,可以当控件来操作,拥有事件、样式、模板。开销比较大。

image.png



高性能画图应该使用 Geometry + DrawingContext + DrawingVisual 的组合 ,而不是 Shape 类。


Shape类最慢

Geometry(中等)

DrawingContext + DrawingVisual(最快)


- DrawingContext 命令式绘制,类似 GDI+

- 适合大量图形 (数千个)


image.png


DrawingContext 和 DrawingVisual 是 WPF 中高性能图形绘制的两个关键类,它们的关系如下:


 核心概念

 DrawingVisual(画布)

- 是什么 :一个轻量级的可视化元素

- 继承关系 : Visual → ContainerVisual → DrawingVisual

- 特点 :不是 FrameworkElement ,没有 UI 开销(无事件、样式、模板)

- 作用 :作为容器,存储绘制的内容


 DrawingContext(画笔)

- 是什么 :用于在 DrawingVisual 上绘制内容的工具

- 特点 :类似 GDI+ 的 Graphics 对象

- 作用 :提供绘制方法(DrawLine、DrawEllipse、DrawGeometry 等)

- 使用方式 :通过 DrawingVisual.RenderOpen() 获取,使用后必须 Dispose


 关系图

DrawingVisual (画布)
    ↓ RenderOpen()
DrawingContext (画笔)
    ↓ 绘制命令
    ↓ Close()
DrawingVisual (包含绘制结果)



image.png

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

«    2026年2月    »
1
2345678
9101112131415
16171819202122
232425262728
控制面板
您好,欢迎到访网站!
  查看权限
网站分类
搜索
最新留言
文章归档
网站收藏
友情链接

Powered By Z-BlogPHP 1.7.3

Copyright www.skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864