自学内容网 自学内容网

跨平台WPF框架Avalonia教程 四

布局

面板(Panel)

Avalonia 包含一组派生自 Panel 的元素。这些 Panel 元素可实现许多复杂的布局。例如,可以使用 StackPanel 元素轻松地堆叠元素,而使用 Canvas 则可以实现更复杂和自由流动的布局。

以下表格总结了可用的 Panel 控件:

名称描述
Panel将所有子元素布局以填充 Panel 的边界
Canvas定义一个区域,您可以在其中使用相对于 Canvas 区域的坐标明确定位子元素
DockPanel定义一个区域,其中您可以相对于彼此将子元素水平或垂直地排列
Grid定义由列和行组成的灵活网格区域
RelativePanel将子元素相对于其他元素或面板本身排列
StackPanel将子元素排列成一行,可以是水平或垂直方向
WrapPanel将子元素按从左到右的顺序放置,当内容到达容器框的边缘时,将在下一行中断。后续排序顺序是顺序从上到下或从右到左,这取决于 Orientation 属性的值。

在 WPF 中,Panel 是一个抽象类,通常使用没有行/列的 Grid 来布局多个控件以填充可用空间。在 Avalonia 中,Panel 是一个可用的控件,其布局行为与没有行/列的 Grid 相同,但运行时占用更少的资源。

元素边界框

在考虑 Avalonia 中的布局时,了解包围所有元素的边界框很重要。布局系统处理的每个 Control 可以看作是一个矩形,该矩形被插入布局。Bounds 属性返回元素布局分配的边界。矩形的大小通过计算可用的屏幕空间、任何约束的大小、布局特定属性(如 margin 和 padding)以及父 Panel 元素的个体行为来确定。处理这些数据,布局系统能够计算特定 Panel 的所有子元素的位置。重要的是要记住,定义在父元素上的大小特性,例如 Border 上的特性,会影响其子元素。

布局系统

简单来说,布局是一种递归系统,导致元素被大小化、定位和绘制。更具体地说,布局描述了对 Panel 元素的 Children 集合的成员进行测量和排列的过程。布局是一个密集的过程。Children 集合越大,必须进行的计算越多。还可以根据拥有集合的 Panel 元素定义的布局行为引入复杂性。一个相对简单的 Panel,例如 Canvas,可以比一个更复杂的 Panel,例如 Grid,具有更好的性能。

每次子控件更改其位置时,它都有可能触发布局系统的新传递。因此,了解可以调用布局系统的事件很重要,因为不必要的调用可能会导致应用程序性能下降。下面描述了在调用布局系统时发生的过程。

  1. 子 UIElement 通过首先测量其核心属性来开始布局过程。
  2. 评估在 Control 上定义的大小属性,例如 WidthHeight 和 Margin
  3. 应用 Panel 特定的逻辑,例如 Dock 方向或堆叠的 Orientation
  4. 在所有子元素进行测量后,进行内容的排列。
  5. 在屏幕上绘制 Children 集合。
  6. 如果向集合中添加了其他 Children,则再次调用此过程。

此过程及其调用方式在以下部分中有更详细的定义。

测量和排列子元素

布局系统对 Children 集合的每个成员完成两个传递:测量传递和排列传递。每个子 Panel 提供其自己的 MeasureOverride 和 ArrangeOverride 方法,以实现其自己的特定布局行为。

在测量传递期间,对 Children 集合的每个成员进行评估。该过程从调用 Measure 方法开始。此方法在父 Panel 元素的实现中调用,不必显式调用以进行布局。

首先,评估 Visual 的本机大小属性,例如 Clip 和 IsVisible。这将生成传递给 MeasureCore 的约束。

然后,处理影响约束值的框架属性。这些属性通常描述底层 Control 的大小特性,例如其 HeightWidth 和 Margin。每个这些属性都可以改变显示元素所需的空间。然后,使用约束调用 MeasureOverride

由于 Bounds 是计算值,因此您应该注意,由于布局系统的各种操作,它可能会发生多次或增量的报告更改。布局系统可能正在为子元素计算所需的测量空间、父元素的约束等。

测量传递的最终目标是让子元素确定其 DesiredSize,这在 MeasureCore 调用期间发生。Measure 将 DesiredSize 值存储以在内容排列传递中使用。

排列传递从调用 Arrange 方法开始。在排列传递期间,父 Panel 元素生成表示子元素边界的矩形。该值传递给 ArrangeCore 方法进行处理。

ArrangeCore 方法评估子元素的 DesiredSize,并评估任何可能影响元素渲染大小的附加 marginArrangeCore 生成一个排列大小,将其作为参数传递给 Panel 的 ArrangeOverride 方法。ArrangeOverride 生成子元素的 finalSize。最后,ArrangeCore 方法对边距和对齐等偏移属性进行最后评估,并将子元素放置在其布局插槽中。子元素不必(也经常不会)填充整个分配的空间。然后,将控件返回给父 Panel,布局过程完成。

Alignment、Margin 和 Padding

Avalonia 控件暴露了用于精确定位子元素的几个属性。本章节讨论了四个最重要的属性:HorizontalAlignmentMarginPaddingVerticalAlignment。理解这些属性的效果很重要,因为它们是控制元素在Avalonia应用程序中的位置的基础。

元素定位

Avalonia定位元素有许多使用方式。然而,实现理想的布局不仅仅是选择正确的Panel元素,精确控制定位还需要理解HorizontalAlignmentMarginPaddingVerticalAlignment属性。

下图展示了一个使用了多个定位属性的布局方案。

乍一看,本图中的Button元素可能是随机放置的。然而,它们的位置实际上是通过组合使用边距(margin)、对齐(alignment)和填充(padding)来精确控制的。

以下示例描述了如何创建上图中的布局。一个Border元素封装了一个父元素StackPanelPadding值为15个设备独立像素。这就说明了围绕子StackPanel的狭窄的LightBlue部分。StackPanel的子元素用于说明本章节中详细介绍的每个不同的定位属性。三个Button元素用于演示MarginHorizontalAlignment属性。

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Class="AvaloniaApplication2.MainWindow"
        Title="AvaloniaApplication2">
  <Border Background="LightBlue"
          BorderBrush="Black"
          BorderThickness="2"
          Padding="15">
    <StackPanel Background="White"
                HorizontalAlignment="Center"
                VerticalAlignment="Top">
      <TextBlock Margin="5,0"
                 FontSize="18"
                 HorizontalAlignment="Center">
        Alignment, Margin and Padding Sample
      </TextBlock>
      <Button HorizontalAlignment="Left" Margin="20">Button 1</Button>
      <Button HorizontalAlignment="Right" Margin="10">Button 2</Button>
      <Button HorizontalAlignment="Stretch">Button 3</Button>
    </StackPanel>
  </Border>
</Window>

下图提供了上述示例中使用的各种定位属性的全貌图。本章节的后续部分会更详细地描述如何使用每个定位属性。

Positioning Properties

理解Alignment属性

HorizontalAlignmentVerticalAlignment属性描述了一个子元素应该如何在父元素分配的布局空间内定位。通过一起使用这些属性,你可以精确地定位子元素。例如,DockPanel的子元素可以指定四种不同的水平对齐方式。LeftRightCenter或者Stretch(拉伸)以填补可用空间。类似的值也可用于垂直定位。

元素上明确设置的HeightWidth属性的优先级高于Stretch属性。如果明确设置了HeightWidth,再将HorizontalAlignment设置为Stretch,这样会忽略Stretch属性。

HorizontalAlignment属性

HorizontalAlignment属性声明了要应用于子元素的水平对齐特性。下表列出了HorizontalAlignment属性的可选值。

成员描述
Left子元素与父元素分配的布局空间的左侧对齐。
Center子元素与父元素分配的布局空间的中心对齐。
Right子元素与父元素分配的布局空间的右侧对齐。
Stretch (默认)子元素被拉伸以填充父元素分配的布局空间。明确的WidthHeight值优先级更高。

下面的示例展示了如何将HorizontalAlignment属性应用于Button元素。为了更好地说明各种渲染行为,每种特性值的效果都被展示了出来。

<Button HorizontalAlignment="Left">Button 1 (Left)</Button>
<Button HorizontalAlignment="Right">Button 2 (Right)</Button>
<Button HorizontalAlignment="Center">Button 3 (Center)</Button>
<Button HorizontalAlignment="Stretch">Button 4 (Stretch)</Button>

前面的代码生成了与下图类似的布局。每种HorizontalAlignment值的定位效果在图中可见。

VerticalAlignment属性

VerticalAlignment属性声明了要应用于子元素的垂直对齐特性。下表列出了VerticalAlignment属性的可选值。

成员描述
Top子元素与父元素分配的布局空间的顶部对齐。
Center子元素与父元素分配的布局空间的中心对齐。
Bottom子元素与父元素分配的布局空间的底部对齐。
Stretch(默认)子元素被拉伸以填充父元素分配的布局空间。明确的WidthHeight值优先级更高。

下面的示例展示了如何将VerticalAlignment属性应用于Button元素。为了更好地说明各种渲染行为,每种特性值的效果都被展示了出来。在本示例中,使用具有可见网格线的Grid元素作为父元素,以更好地说明每种属性值的布局行为。

<Border Background="LightBlue" BorderBrush="Black" BorderThickness="2" Padding="15">
    <Grid Background="White" ShowGridLines="True">
      <Grid.RowDefinitions>
        <RowDefinition Height="25"/>
        <RowDefinition Height="50"/>
        <RowDefinition Height="50"/>
        <RowDefinition Height="50"/>
        <RowDefinition Height="50"/>
      </Grid.RowDefinitions>
      <TextBlock Grid.Row="0" Grid.Column="0"
                 FontSize="18"
                 HorizontalAlignment="Center">
        VerticalAlignment Sample
      </TextBlock>
      <Button Grid.Row="1" Grid.Column="0" VerticalAlignment="Top">Button 1 (Top)</Button>
      <Button Grid.Row="2" Grid.Column="0" VerticalAlignment="Bottom">Button 2 (Bottom)</Button>
      <Button Grid.Row="3" Grid.Column="0" VerticalAlignment="Center">Button 3 (Center)</Button>
      <Button Grid.Row="4" Grid.Column="0" VerticalAlignment="Stretch">Button 4 (Stretch)</Button>
    </Grid>
</Border>

前面的代码生成了与下图类似的布局。每种VerticalAlignment值的定位效果在图中可见。

理解Margin属性

Margin属性描述了元素与其子元素或同级元素之间的距离。Margin值可以是相同的,通过使用像Margin="20"的语法,元素将使用相同的20个设备独立像素的MarginMargin值也可以是四个不同的值,每个值描述了应用于左、上、右和下的不同边距(按顺序),如Margin="0,10,5,25"。正确使用Margin属性可以非常精确地控制元素的渲染位置及其相邻元素和子元素的渲染位置。

非零的边距应用在元素的Bounds之外的空间。

下面的示例展示了如何在一组Button元素周围应用相同的边距。这些Button元素的间距是均匀的,每个方向都有10像素的边距缓冲。

<Button Margin="10">Button 7</Button>
<Button Margin="10">Button 8</Button>
<Button Margin="10">Button 9</Button>

在许多情况下,统一的边距是不合适的。在这些情况下,可以应用非统一间距。以下示例展示了如何将非统一边距应用于子元素。边距按该顺序描述:左、上、右、下。

<Button Margin="0,10,0,10">Button 1</Button>
<Button Margin="0,10,0,10">Button 2</Button>
<Button Margin="0,10,0,10">Button 3</Button>

理解Padding属性

Padding在大多数方面与Margin相似。Padding属性仅暴露在少数类上,主要是为了方便。BorderTemplatedControl、和TextBlock是暴露了Padding属性的类的范例。Padding属性通过指定的Thickness值扩大了子元素的有效尺寸。

以下示例展示了如何将Padding应用于父Border元素。

<Border Background="LightBlue"
        BorderBrush="Black"
        BorderThickness="2"
        CornerRadius="45"
        Padding="25">

在应用程序中使用Alignment、Margin和Padding

HorizontalAlignmentMarginPaddingVerticalAlignment提供创建复杂UI所需的定位控制。您可以使用每个属性的效果来改变子元素的位置,从而实现灵活地创建动态应用程序和提升用户体验。

下面的示例演示了本章节中详细介绍的每个概念。在本章节第一个示例的基础上,这个示例添加了一个Grid元素作为第一个示例中Border的子元素。Padding应用于父Border元素。Grid用于三个子StackPanel元素之间划分空间。Button元素再次被用来展示MarginHorizontalAlignment的各种效果。TextBlock元素被添加到每个ColumnDefinition中,以更好地定义应用于每一列中Button元素的各种属性。

<Border Background="LightBlue"
        BorderBrush="Black"
        BorderThickness="2"
        CornerRadius="45"
        Padding="25">
    <Grid Background="White" ShowGridLines="True">
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="Auto"/>
      </Grid.ColumnDefinitions>

    <StackPanel Grid.Column="0" Grid.Row="0"
                HorizontalAlignment="Left"
                Name="StackPanel1"
                VerticalAlignment="Top">
        <TextBlock FontSize="18" HorizontalAlignment="Center" Margin="0,0,0,15">StackPanel1</TextBlock>
        <Button Margin="0,10,0,10">Button 1</Button>
        <Button Margin="0,10,0,10">Button 2</Button>
        <Button Margin="0,10,0,10">Button 3</Button>
        <TextBlock>ColumnDefinition.Width="Auto"</TextBlock>
        <TextBlock>StackPanel.HorizontalAlignment="Left"</TextBlock>
        <TextBlock>StackPanel.VerticalAlignment="Top"</TextBlock>
        <TextBlock>StackPanel.Orientation="Vertical"</TextBlock>
        <TextBlock>Button.Margin="0,10,0,10"</TextBlock>
    </StackPanel>

    <StackPanel Grid.Column="1" Grid.Row="0"
                HorizontalAlignment="Stretch"
                Name="StackPanel2"
                VerticalAlignment="Top"
                Orientation="Vertical">
        <TextBlock FontSize="18" HorizontalAlignment="Center" Margin="0,0,0,15">StackPanel2</TextBlock>
        <Button Margin="10,0,10,0">Button 4</Button>
        <Button Margin="10,0,10,0">Button 5</Button>
        <Button Margin="10,0,10,0">Button 6</Button>
        <TextBlock HorizontalAlignment="Center">ColumnDefinition.Width="*"</TextBlock>
        <TextBlock HorizontalAlignment="Center">StackPanel.HorizontalAlignment="Stretch"</TextBlock>
        <TextBlock HorizontalAlignment="Center">StackPanel.VerticalAlignment="Top"</TextBlock>
        <TextBlock HorizontalAlignment="Center">StackPanel.Orientation="Horizontal"</TextBlock>
        <TextBlock HorizontalAlignment="Center">Button.Margin="10,0,10,0"</TextBlock>
    </StackPanel>

    <StackPanel Grid.Column="2" Grid.Row="0"
                HorizontalAlignment="Left"
                Name="StackPanel3"
                VerticalAlignment="Top">
        <TextBlock FontSize="18" HorizontalAlignment="Center" Margin="0,0,0,15">StackPanel3</TextBlock>
        <Button Margin="10">Button 7</Button>
        <Button Margin="10">Button 8</Button>
        <Button Margin="10">Button 9</Button>
        <TextBlock>ColumnDefinition.Width="Auto"</TextBlock>
        <TextBlock>StackPanel.HorizontalAlignment="Left"</TextBlock>
        <TextBlock>StackPanel.VerticalAlignment="Top"</TextBlock>
        <TextBlock>StackPanel.Orientation="Vertical"</TextBlock>
        <TextBlock>Button.Margin="10"</TextBlock>
    </StackPanel>
  </Grid>
</Border>

编译时,前面的应用程序生成的UI与下图类似。各种属性值的影响在元素之间的间距中很明显,每列元素的重要属性值展示在TextBlock元素中。

Several positioning properties in one application

Panels Overview

Panel 元素是控制元素的呈现方式的组件,包括元素的大小和尺寸、位置以及子内容的排列。Avalonia UI 提供了许多预定义的 Panel 元素,同时也支持构建自定义的 Panel 元素。

Panel 类

Panel 是所有在 Avalonia 中提供布局支持的元素的基类。派生的 Panel 元素用于在 XAML 和代码中定位和排列元素。

Avalonia 包含一套全面的派生面板实现,支持许多复杂的布局。这些派生类公开了属性和方法,以支持大多数标准的 UI 场景。无法找到满足需求的子元素排列行为的开发人员可以通过重写 ArrangeOverride 和 MeasureOverride 方法来创建新的布局。有关自定义布局行为的更多信息,请参阅 Create a Custom Panel

Panel 公共成员

所有 Panel 元素支持 Control 定义的基本大小和定位属性,包括 HeightWidthHorizontalAlignmentVerticalAlignment 和 Margin。有关由 Control 定义的定位属性的更多信息,请参阅 Alignment、Margin 和 Padding

Panel 还公开了其他一些属性,在理解和使用布局方面非常重要。Background 属性用于使用 Brush 填充派生面板元素边界之间的区域。Children 表示 Panel 所包含的子元素集合。

附加属性

派生的面板元素广泛使用附加属性。附加属性是一种特殊形式的依赖属性,它没有常规的公共语言运行时 (CLR) 属性 "包装器"。附加属性在 XAML 中有一种特殊的语法,后面的示例中会看到。

附加属性的一个用途是允许子元素存储父元素实际定义的属性的唯一值。这个功能的一个应用是让子元素告诉父元素它们希望在 UI 中如何呈现,这对应用程序布局非常有用。

用户界面面板

Avalonia 中有几个优化支持 UI 场景的面板类:PanelCanvasDockPanelGridStackPanelWrapPanel 和 RelativePanel。这些面板元素易于使用,足够灵活且可扩展,适用于大多数应用程序。

Canvas

Canvas 元素允许按绝对 x- 和 y- 坐标定位内容。元素可以绘制在唯一位置;或者,如果元素占据相同的坐标,则在标记中出现的顺序决定元素的绘制顺序。

Canvas 提供了最灵活的布局支持。Height 和 Width 属性用于定义画布的区域,其中的元素被赋予相对于父 Canvas 区域的绝对坐标。四个附加属性 Canvas.LeftCanvas.TopCanvas.Right 和 Canvas.Bottom 允许精确地控制对象在 Canvas 内的位置,从而使开发人员可以精确定位和排列元素在屏幕上的位置。

ClipToBounds 在 Canvas 中

Canvas 可以将子元素定位在屏幕上的任何位置,甚至在超出其自定义的 Height 和 Width 的坐标。此外,Canvas 不受其子元素大小的影响。因此,子元素有可能覆盖位于父 Canvas 限界矩形之外的其他元素。Canvas 的默认行为是允许子元素绘制在父 Canvas 限界之外。如果不希望出现这种情况,可以将 ClipToBounds 属性设置为 true## RelativePanel

定义和使用 Canvas

使用 XAML 或代码可以简单地实例化一个 Canvas。下面的示例演示了如何使用 Canvas 来绝对定位内容。该代码生成了三个大小为 100 像素的正方形。第一个正方形为红色,其左上角的 (x, y) 位置被指定为 (0, 0)。第二个正方形为绿色,其左上角位置为 (100, 100),刚好在第一个正方形的右下方。第三个正方形为蓝色,其左上角位置为 (50, 50),因此覆盖了第一个正方形的右下象限和第二个正方形的左上象限。由于第三个正方形是最后布局的,它出现在其他两个正方形的上方,即重叠部分采用第三个正方形的颜色。

StackPanel Example

  • XAML
  • C#
<Canvas Height="400" Width="400">
  <Canvas Height="100" Width="100" Top="0" Left="0" Background="Red"/>
  <Canvas Height="100" Width="100" Top="100" Left="100" Background="Green"/>
  <Canvas Height="100" Width="100" Top="50" Left="50" Background="Blue"/>
</Canvas>

DockPanel

DockPanel 元素使用附加属性 DockPanel.Dock 来设置子内容元素在容器边缘的位置。当 DockPanel.Dock 设置为 Top 或 Bottom 时,它会将子元素放置在彼此的上方或下方。当 DockPanel.Dock 设置为 Left 或 Right 时,它会将子元素放置在彼此的左侧或右侧。LastChildFill 属性决定了最后一个作为 DockPanel 子元素添加的元素的位置。

你可以使用 DockPanel 来定位一组相关的控件,例如一组按钮。或者,你可以使用它来创建一个“分栏式”的用户界面。

自适应大小

如果没有指定 DockPanel 的 Height 和 Width 属性,它的大小将根据其内容来确定。大小可以根据其子元素的大小进行增长或减小。然而,当指定了这些属性并且没有足够的空间来容纳下一个指定的子元素时,DockPanel 不会显示该子元素或随后的子元素,并且不会对随后的子元素进行测量。

LastChildFill 属性

默认情况下,DockPanel 元素的最后一个子元素将“填充”剩余的未分配空间。如果不希望出现这种情况,可以将 LastChildFill 属性设置为 false

定义和使用 DockPanel

下面的示例演示了如何使用 DockPanel 来划分空间。五个 Border 元素被添加为 DockPanel 的子元素。每个元素使用 DockPanel 的不同定位属性来划分空间。最后一个元素将“填充”剩余的未分配空间。

StackPanel Example

  • XAML
  • C#
<DockPanel LastChildFill="True">
  <Border Height="25" Background="SkyBlue" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top">
    <TextBlock Foreground="Black">Dock = "Top"</TextBlock>
  </Border>
  <Border Height="25" Background="SkyBlue" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top">
    <TextBlock Foreground="Black">Dock = "Top"</TextBlock>
  </Border>
  <Border Height="25" Background="LemonChiffon" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Bottom">
    <TextBlock Foreground="Black">Dock = "Bottom"</TextBlock>
  </Border>
  <Border Width="200" Background="PaleGreen" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Left">
    <TextBlock Foreground="Black">Dock = "Left"</TextBlock>
  </Border>
  <Border Background="White" BorderBrush="Black" BorderThickness="1">
    <TextBlock Foreground="Black">This content will "Fill" the remaining space</TextBlock>
  </Border>
</DockPanel>

Grid

Grid 元素合并了绝对定位和表格数据控件的功能。Grid 允许您轻松地定位和样式化元素。它允许您定义灵活的行和列分组,并且甚至可以在多个 Grid 元素之间共享大小信息。

列和行的大小行为

在 Grid 中定义的列和行可以利用 Star 大小调整功能,以便按比例分配剩余空间。当在行或列的高度或宽度中选择 Star 时,该列或行将按比例获得剩余的可用空间。这与 Auto 形式不同,后者会根据列或行中内容的大小均匀分配空间。在 XAML 中,这个值表示为 * 或 2*。在第一种情况下,行或列将获得一倍的可用空间,在第二种情况下,将获得两倍的可用空间,依此类推。通过将这种技术与 HorizontalAlignment 和 VerticalAlignment 的值设置为 Stretch 结合使用,可以按屏幕空间的百分比划分布局空间。Grid 是唯一可以以这种方式分配空间的布局面板。

定义和使用 Grid

下面的示例演示了如何构建一个类似于 Windows 开始菜单中的“运行”对话框的用户界面。

  • XAML
  • C#
<Grid Background="Gainsboro" 
      HorizontalAlignment="Left" 
      VerticalAlignment="Top" 
      Width="425" 
      Height="165"
      ColumnDefinitions="Auto,*,*,*,*"
      RowDefinitions="Auto,Auto,*,Auto">
    
    <Image Grid.Row="0" Grid.Column="0" Source="{Binding runicon}" />
    
    <TextBlock Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="4" 
               Text="Type the name of a program, folder, document, or Internet resource, and Windows will open it for you." 
               TextWrapping="Wrap" />
               
    <TextBlock Grid.Row="1" Grid.Column="0" Text="Open:" />
    
    <TextBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="5" />
    
    <Button Grid.Row="3" Grid.Column="2" Content="OK" Margin="10,0,10,15" />
    
    <Button Grid.Row="3" Grid.Column="3" Content="Cancel" Margin="10,0,10,15" />
    
    <Button Grid.Row="3" Grid.Column="4" Content="Browse ..." Margin="10,0,10,15" />
</Grid>

StackPanel

StackPanel 允许您在指定的方向上“堆叠”元素。默认的堆叠方向是垂直的。Orientation 属性可用于控制内容的流向。

StackPanel 对比 DockPanel

虽然 DockPanel 也可以“堆叠”子元素,但在某些使用场景中,DockPanel 和 StackPanel 的结果并不相同。例如,在 DockPanel 中,子元素的顺序会影响它们的大小,而在 StackPanel 中则不会。这是因为 StackPanel 在堆叠方向上测量的大小是 PositiveInfinity,而 DockPanel 仅测量可用大小。

定义和使用 StackPanel

下面的示例演示了如何使用 StackPanel 创建一组垂直定位的按钮。如果要进行水平定位,请将 Orientation 属性设置为 Horizontal

StackPanel Example

  • XAML
  • C#
 <StackPanel HorizontalAlignment="Center" 
                VerticalAlignment="Top"
                Spacing="25">
        <Button Content="Button 1" />
        <Button Content="Button 2" />
        <Button Content="Button 3" />
    </StackPanel>

WrapPanel

WrapPanel 用于按从左到右的顺序定位子元素,并在其父容器的边缘到达时将内容折行到下一行。内容可以水平或垂直方向上定位。WrapPanel 在简单的流式界面场景中非常有用。它还可以用于对其所有子元素应用统一的大小。

下面的示例演示了如何创建一个 WrapPanel 来显示 Button 控件,并在它们到达容器边缘时进行折行。

StackPanel Example

  • XAML
  • C#
<Border HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="Black" BorderThickness="2">
  <WrapPanel Background="LightBlue" Width="200" Height="100">
    <Button Width="200">Button 1</Button>
    <Button>Button 2</Button>
    <Button>Button 3</Button>
    <Button>Button 4</Button>
  </WrapPanel>
</Border>

嵌套面板元素

Panel 元素可以相互嵌套,以创建复杂的布局。这在某些情况下非常有用,例如一个 Panel 对于 UI 的某个部分可能非常合适,但对于另一个部分可能不符合需求。

在您的应用程序中,理论上可以无限嵌套面板元素,但通常最好仅使用实际需要的面板元素来实现所需的布局。在许多情况下,由于其作为布局容器的灵活性,可以使用 Grid 元素来替代嵌套面板。这样可以通过将不必要的元素排除在布局树之外,提高应用程序的性能。

UniformGrid

UniformGrid 是一种提供统一网格布局的面板类型。这意味着它会将其子元素布局在一个网格中,该网格中的所有单元格大小相同。与标准的 Grid 不同,UniformGrid 不支持显式行和列,也不提供 Grid.Row 或 Grid.Column 附加属性。

UniformGrid 的主要用途是在需要以网格格式显示项目集合的情况下,每个项目占用相同的空间。

UniformGrid 属性

  • 行和列UniformGrid 使用 Rows 和 Columns 属性来确定其子元素的布局。如果只设置其中一个属性,UniformGrid 将自动计算另一个属性,以创建适合子元素总数的网格。如果两个属性都不设置,UniformGrid 默认为 1 行 1 列的网格。

例如,如果有 12 个项目,并将 Rows 设置为 3,则 UniformGrid 将自动创建 4 列。如果将 Columns 设置为 4,则它将自动创建 3 行。

  • FirstColumnFirstColumn 属性允许您在网格的第一行中留下一定数量的空单元格。

定义和使用 UniformGrid

下面的示例演示了如何定义和使用 UniformGrid。该示例创建了一个 3 行 4 列的 UniformGrid,并将 12 个矩形作为子元素添加进去。

StackPanel Example

  • XAML
  • C#
<UniformGrid Rows="3" Columns="4">
  <Rectangle Width="50" Height="50" Fill="#330000"/>
  <Rectangle Width="50" Height="50" Fill="#660000"/>
  <Rectangle Width="50" Height="50" Fill="#990000"/>
  <Rectangle Width="50" Height="50" Fill="#CC0000"/>
  <Rectangle Width="50" Height="50" Fill="#FF0000"/>
  <Rectangle Width="50" Height="50" Fill="#FF3300"/>
  <Rectangle Width="50" Height="50" Fill="#FF6600"/>
  <Rectangle Width="50" Height="50" Fill="#FF9900"/>
  <Rectangle Width="50" Height="50" Fill="#FFCC00"/>
  <Rectangle Width="50" Height="50" Fill="#FFFF00"/>
  <Rectangle Width="50" Height="50" Fill="#FFFF33"/>
  <Rectangle Width="50" Height="50" Fill="#FFFF66"/>
</UniformGrid>

在上面的示例中,每个 Rectangle 被自动分配到网格中的一个单元格,按照它们被添加的顺序进行分配。

 


原文地址:https://blog.csdn.net/XiaoWang_csdn/article/details/143833190

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!