布局面板

布局面板是用来为应用中的 UI 元素排列和分组的容器。 内置 XAML 布局面板包括 RelativePanel、StackPanelGridVariableSizedWrapGridCanvas。 在这里,我们将介绍每个面板,并演示如何使用它来布局 XAML UI 元素。

选择布局面板时需要考虑以下几个事项:

  • 面板如何定位其子元素。
  • 面板如何调整其子元素的大小。
  • 重叠子元素的分层方式(z 顺序)。
  • 创建所需布局所需的嵌套面板元素的数量和复杂性。

示例

WinUI 2 库
WinUI 库

如果已安装 WinUI 2 库应用,请参阅 RelativePanel、StackPanelGridVariableSizedWrapGridCanvas

面板属性

在讨论各个面板之前,让我们了解一下所有面板都具有的一些常见属性。

面板附加属性

大多数 XAML 布局面板使用附加属性让其子元素告知父面板如何在 UI 中定位它们。 附加属性使用语法 AttachedPropertyProvider.PropertyName。 如果面板嵌套在其他面板内,则仅由最直接的父面板解释指定布局特征的 UI 元素上的附加属性。

下面是有关如何在 XAML 中的 Button 控件上设置 Canvas.Left 附加属性的示例。 这会通知父画布,按钮应放置在画布左边缘 50 个有效像素。

<Canvas>
  <Button Canvas.Left="50">Hello</Button>
</Canvas>

有关附加属性的详细信息,请参阅附加属性概述

面板边框

RelativePanel、StackPanel 和网格面板定义边框属性,使你可以在面板周围绘制边框,而无需将它们包装到其他 Border 元素中。 边框属性为 BorderBrushBorderThicknessCornerRadiusPadding

下面是如何在网格上设置边框属性的示例。

<Grid BorderBrush="Blue" BorderThickness="12" CornerRadius="12" Padding="12">
    <TextBlock Text="Hello World!"/>
</Grid>

带边框的网格

使用内置边框属性可减少 XAML 元素计数,从而提高应用的 UI 性能。 有关布局面板和 UI 性能的详细信息,请参阅 “优化 XAML 布局”。

RelativePanel

RelativePanel 允许你设置 UI 元素的布局,方法是指定它们相对于其他元素的位置和相对于面板的位置。 默认情况下,元素位于面板的左上角。 可以将 RelativePanel 与 VisualStateManagerAdaptiveTrigger 一起使用,以针对不同的窗口大小重新排列 UI。

此表显示了可用于相对于面板或其他元素对齐某个元素的附加属性。

面板对齐 同级对齐方式 同级位置
AlignTopWithPanel AlignTopWith Above
AlignBottomWithPanel AlignBottomWith Below
AlignLeftWithPanel AlignLeftWith LeftOf
AlignRightWithPanel AlignRightWith RightOf
AlignHorizontalCenterWithPanel AlignHorizontalCenterWith  
AlignVerticalCenterWithPanel AlignVerticalCenterWith  

此 XAML 演示如何排列 RelativePanel 中的元素。

<RelativePanel BorderBrush="Gray" BorderThickness="1">
    <Rectangle x:Name="RedRect" Fill="Red" Height="44" Width="44"/>
    <Rectangle x:Name="BlueRect" Fill="Blue"
               Height="44" Width="88"
               RelativePanel.RightOf="RedRect" />

    <Rectangle x:Name="GreenRect" Fill="Green" 
               Height="44"
               RelativePanel.Below="RedRect" 
               RelativePanel.AlignLeftWith="RedRect" 
               RelativePanel.AlignRightWith="BlueRect"/>
    <Rectangle Fill="Orange"
               RelativePanel.Below="GreenRect" 
               RelativePanel.AlignLeftWith="BlueRect" 
               RelativePanel.AlignRightWithPanel="True"
               RelativePanel.AlignBottomWithPanel="True"/>
</RelativePanel>

结果如下所示。

相对面板

以下是一些在调整矩形大小时需要注意的事项:

  • 红色矩形的显式大小为 44x44。 它放置在面板的左上角,这是默认位置。
  • 绿色矩形的显式高度为 44。 其左侧与红色矩形对齐,右侧与蓝色矩形对齐,确定其宽度。
  • 橙色矩形未给定显式大小。 其左侧与蓝色矩形对齐。 它的右边缘和下边缘与面板的边缘对齐。 其大小由这些对齐方式确定,它将在调整面板大小时调整大小。

StackPanel

StackPanel 可以将其子元素按水平或垂直方向排列到单行中的布局面板。 StackPanel 通常用于在页面上排列一小部分 UI。

可以使用 Orientation 属性指定子元素的方向。 默认方向为 Vertical

以下 XAML 演示如何创建项的垂直 StackPanel。

<StackPanel>
    <Rectangle Fill="Red" Height="44"/>
    <Rectangle Fill="Blue" Height="44"/>
    <Rectangle Fill="Green" Height="44"/>
    <Rectangle Fill="Orange" Height="44"/>
</StackPanel>

结果如下所示。

堆栈面板

在 StackPanel 中,如果未显式设置子元素的大小,它将拉伸以填充可用宽度(或高度(如果方向为 水平)。 在此示例中,未设置矩形的宽度。 矩形展开以填充 StackPanel 的整个宽度。

网格

Grid 面板支持动态布局并允许你以多行或多列布局排列控件。 可以通过使用 RowDefinitionsColumnDefinitions 属性来指定 Grid 的行和列。

要将对象放置到 Grid 的特定单元格中,请使用 Grid.ColumnGrid.Row 附加属性。

要使内容分散到多个行和列中,请使用 Grid.RowSpanGrid.ColumnSpan 附加属性。

此 XAML 示例演示如何创建包含两行和两列的网格。

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition Height="44"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Rectangle Fill="Red" Width="44"/>
    <Rectangle Fill="Blue" Grid.Row="1"/>
    <Rectangle Fill="Green" Grid.Column="1"/>
    <Rectangle Fill="Orange" Grid.Row="1" Grid.Column="1"/>
</Grid>

结果如下所示。

网格

在此示例中,大小调整的工作方式如下所示:

  • 第二行的显式高度为 44 个有效像素。 默认情况下,第一行的高度填充剩余的空间。
  • 第一列的宽度设置为 “自动”,因此其子列的宽度是一样宽。 在这种情况下,宽度为 44 个有效像素,以容纳红色矩形的宽度。
  • 矩形上没有其他大小限制,因此每个矩形都拉伸以填充其所属的网格单元格。

可以使用“自动”或“星型调整”在列或行内分配空间。 使用自动调整大小让 UI 元素调整大小以适应其内容或父容器。 还可以对网格的行和列使用自动大小调整。 若要使用自动大小调整,请将 UI 元素的高度和/或宽度设置为 “自动”。

使用比例大小调整(也称为 星型调整)按加权比例在网格的行和列之间分配可用空间。 在 XAML 中,比例缩放值用 * 表示(或使用 n* 表示加权比例缩放)。 例如,若要在两列布局中指定一列比另一列宽五倍,则在 ColumnDefinition 元素中对 Width 属性分别使用“5*”和“*”

本示例将网格中的固定大小、自动大小和比例大小与 4 列组合在一起。

大小调整 说明
Column_1 Auto 该列的大小将适合其内容。
Column_2 * 计算自动列后,该列将获取剩余宽度的一部分。 Column_2宽度为Column_4的一半。
Column_3 44 列宽为 44 像素。
Column_4 2* 计算自动列后,该列将获取剩余宽度的一部分。 Column_4宽度为Column_2两倍。

默认列宽为“*”,因此无需为第二列显式设置此值。

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition/>
        <ColumnDefinition Width="44"/>
        <ColumnDefinition Width="2*"/>
    </Grid.ColumnDefinitions>
    <TextBlock Text="Column 1 sizes to its content." FontSize="24"/>
</Grid>

在 Visual Studio XAML 设计器中,结果如下所示。

Visual Studio 设计器中的 4 列网格

VariableSizedWrapGrid

VariableSizedWrapGrid 是一个网格样式的布局面板,当达到 MaximumRowsOrColumns 值时,网格中的行或列会自动换行至新行或新列。

Orientation 属性指定网格在换行之前是否在行或列中添加其项。 默认方向为 Vertical,这意味着网格将项从上到下添加,直到列已满,然后换行到新列。 当值为 Horizontal 时,网格将项从左到右添加,然后换行到新行。

单元格维度由 ItemHeightItemWidth 指定。 每个单元格的大小相同。 如果未指定 ItemHeight 或 ItemWidth,则第一个单元格大小以适应其内容,而其他每个单元格都是第一个单元格的大小。

可以使用 VariableSizedWrapGrid.ColumnSpanVariableSizedWrapGrid.RowSpan 附加属性来指定子元素应填充的相邻单元格数。

下面介绍如何在 XAML 中使用 VariableSizedWrapGrid。

<VariableSizedWrapGrid MaximumRowsOrColumns="3" ItemHeight="44" ItemWidth="44">
    <Rectangle Fill="Red"/>
    <Rectangle Fill="Blue" 
               VariableSizedWrapGrid.RowSpan="2"/>
    <Rectangle Fill="Green" 
               VariableSizedWrapGrid.ColumnSpan="2"/>
    <Rectangle Fill="Orange" 
               VariableSizedWrapGrid.RowSpan="2" 
               VariableSizedWrapGrid.ColumnSpan="2"/>
</VariableSizedWrapGrid>

结果如下所示。

可变大小换行网格

在此示例中,每列中的最大行数为 3。 第一列仅包含 2 个项目(红色和蓝色矩形),因为蓝色矩形跨越 2 行。 然后,绿色矩形将换行到下一列的顶部。

画布

Canvas 面板使用固定的坐标点定位其子元素并且不支持动态布局。 可以通过在每个元素上设置 Canvas.LeftCanvas.Top 附加属性来指定各个子元素上的点。 父级 Canvas 在布局的 Arrange 传递期间从其子级中读取这些附加属性值。

Canvas 中的对象可以重叠,其中一个对象在另一个对象之上绘制。 默认情况下,Canvas 按声明子对象的顺序呈现子对象,因此最后一个子对象呈现在顶部(每个元素的默认 z 索引为 0)。 这与其他内置面板相同。 但是,Canvas 还支持 可以在每个子元素上设置的 Canvas.ZIndex 附加属性。 可以在代码中设置此属性,以在运行时更改元素的绘制顺序。 具有最高 Canvas.ZIndex 值的元素将最后绘制,因此,在共享相同空间或以任何方式重叠的任何其他元素上绘制。 请注意,会遵循 alpha 值(透明度),因此,即使元素重叠,如果顶部区域具有非最大 alpha 值,则重叠区域中显示的内容可能会混合。

Canvas 不对其子级进行任何大小调整。 每个元素必须指定其大小。

下面是 XAML 中的 Canvas 示例。

<Canvas Width="120" Height="120">
    <Rectangle Fill="Red" Height="44" Width="44"/>
    <Rectangle Fill="Blue" Height="44" Width="44" Canvas.Left="20" Canvas.Top="20"/>
    <Rectangle Fill="Green" Height="44" Width="44" Canvas.Left="40" Canvas.Top="40"/>
    <Rectangle Fill="Orange" Height="44" Width="44" Canvas.Left="60" Canvas.Top="60"/>
</Canvas>

结果如下所示。

画布

使用具有自由裁量权的画布面板。 尽管在某些方案中能够精确控制 UI 中元素的位置是很方便的,但固定定位布局面板会导致 UI 的该区域不太适应整个应用窗口大小的变化。 应用窗口大小可能来自设备方向更改、拆分应用窗口、更改监视器和许多其他用户方案。

ItemsControl 面板

有几个特殊用途面板只能用作 ItemsPanel 来显示 ItemsControl 中的项。 这些是 ItemsStackPanelItemsWrapGridVirtualizingStackPanel WrapGrid 不能将这些面板用于常规 UI 布局。

获取示例代码