WPF之旅(三)- 布局之StackPanel

时间:2023-03-08 17:12:48

说到WPF的界面布局,相信很多朋友都写过Html代码。在WPF中,大多数程序都使用类似Web的(flow)流布局。在使用流布局模型时,各种控件可以按特定的要求来排列,在窗口内容发生变化时,比如窗口大小发生变化,界面可以调整自身以及控件的布局。

WPF的布局原则和HTML比较类似,但也有些不同,下面让我们具体来看看:

WPF布局原则

  1. 不应显示设定元素(如控件)的尺寸: 元素应该可以改变尺寸以适应他们的内容,例如当添加更多文本时按钮应当能够扩展。很多时候我们在HTML中设置MinWidth 或者 MaxWidth之类属性去限制控件的尺寸范围,在WPF也有同样的应用。
  2. 不应使用屏幕坐标指定元素的位置:元素应该由他们的容器根据他们的尺寸、顺序以及其他特定于具体布局容器的信息进行排列。上面所说的意思其实也和HTML中的元素位置设定很类似,虽然很多时候我们在HTML中也使用坐标进行定位,但实际上这样的使用情况非常少。
  3. 布局容器的子元素“共享”可用的空间:如果空间允许,布局容器会根据每个元素的内容尽可能为元素设置更合理的尺寸。它们还会向一个或多个子元素分配多余的空间。这点和HTML中设置各个子元素的宽度和高度很类似,我们可以使用具体的像素(PX)来设置元素尺寸,也可以使用百分比(%)来设置元素所占用的空间,另外子元素为了能填充父元素的空间,可能还对有自动的宽度和高度的调整。
  4. 可嵌套的布局容器:在WPF中典型的用户界面使用Grid面板作为开始,Grid面板可以包含其他布局容器。这点也很像Html中的嵌套,我们可以在<Div>中包含再包含<Span>,也可以在<span>中再包含<label>,类似上面的例子的嵌套情况在WPF中也是很常见的。

 

WPF布局过程

WPF布局包括2个阶段:测量(measure)和排列(arrange)。在测量阶段,布局容器会遍历所有子元素,并询问子元素他们所期望的尺寸,在适合的位置放置子元素。

WPF布局容器

在HTML中我们有多种布局的容器,例如<div>、<table>等等,那么在WPF也存在类似的控件,所有WPF的布局容器都派生自System.Window.Controls.Panel, 下面让我们来看下Panel类的层次结构:

WPF之旅(三)- 布局之StackPanel

WPF提供了大量可用于安排布局的继承自Panel的类,这里我们列举几个最基本的类。与所有WPF空间和大多数可视化元素一样,这些类位于System.Windows.Controls的命名空间中。

名称

说明

StackPanel

在水平或垂直的堆栈中放置元素

WrapPanel

在一系列可换行的行中放置元素

DockPanel

根据容器的整个边界调整元素

Grid

根据不可见的表格在行和列中排列元素,最常用的容器之一

UniformGrid

在不可见,但是强制所有单元格具有相同尺寸的表格中放置元素

Cavas

使用固定坐标绝对定位元素

StackPanel的使用

上面讲到了一些关于布局容器的概念和类的说明,现在让我们依次来看下这些常用的布局容器。

首先我们来看下StackPanel,StackPanel面板是WPF中最简单的面板之一,该面板简单地在单行或列中以堆栈形式放置其子元素,默认情况下面板按自上而下的顺序排列元素,并且使每个元素的高度适合它的内容,下面让我们来看一个测试代码:

<Window x:Class="StackPanelTest.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">
<StackPanel>
<Label>A button click</Label>
<Button>Button 1</Button>
<Button>Button 2</Button>
<Button>Button 3</Button>
<Button>Button 4</Button>
</StackPanel>
</Window>

其运行的结果如下图,所有Button都自上而下排列,按钮的大小刚好足够适应他们内部的文本,所有的元素都被拉伸到StackPanel面板的整个宽度。

WPF之旅(三)- 布局之StackPanel

和HTML的某些控件类似,比如RadioButtonList之类的,我们也可以控制元素的的排列方向,在StackPanel中,我们使用Orientation属性来控制子元素的排列方向:

<StackPanel Orientation="Horizontal">

布局属性

StackPanle的布局属性与HTML的布局容器很类似的,都可以设置对齐方式,外边距,最大最小宽度、高度等。

1. 对齐方式

首先我们来看下对其方式,在StackPanel中如果是垂直方向的排列,那么VerticalAligment属性不起作用,因为所有元素的高度都自动地调整为刚好满足各自需要,但是HorizentalAligment属性非常重要,它决定了各个元素在行的什么位置。HorizentalAligment有4个值可以选择:Left, Center, Right 和 Stretch, 相信熟悉Html代码的朋友来说,前面3个值很容易理解,最后一个值Stretch会将子元素拉伸至整个StackPanel面板的宽度,并且会被设置为默认值,让我们来看下具体的代码:

<StackPanel Orientation="Vertical">
<Label HorizontalAlignment="Center">A button click</Label>
<Button HorizontalAlignment="Left">Button 1</Button>
<Button HorizontalAlignment="Right">Button 2</Button>
<Button>Button 3</Button>
<Button>Button 4</Button>
</StackPanel>

当设置了对其方式后,按钮的长度和位置都发生了变化,如下图:

WPF之旅(三)- 布局之StackPanel

我们看到Button1和Button2设置了对其方式后,他们的位置和按钮的宽度都发生了变化,这些实际上和HTML中元素的对其方式都很类似的,需要注意的就是Stretch对齐方式对拉伸子元素的宽度为整个StackPanel的宽度。

 2. 边距

在我们平时的布局中,一般不会让相邻元素靠得太近,所以在Html中,我们一般会加入Margin这样的CSS样式来控制元素的边距。在WPF中,也有类似的情况,我们可以设置Margin属性来调整元素的边距,代码实例如下:

<Button Margin="5,10,5,4">Button 4</Button>

上面的4个值以逗号分隔,这也和CSS中的设置一样,分别为上,右,下,左。下图为设置了Margin的子元素,相邻的2个子元素之间的距离,为他们各自Margin 之和,代码如下:

<StackPanel Orientation="Vertical">
<Label HorizontalAlignment="Center">A button click</Label>
<Button HorizontalAlignment="Left">Button 1</Button>
<Button HorizontalAlignment="Right">Button 2</Button>
<Button Margin="30">Button 3</Button>
<Button Margin="40">Button 4</Button>
</StackPanel>

运行结果如下图:

WPF之旅(三)- 布局之StackPanel

我们可以在XAML中设置Margin,也可以在C#代码中声明,在代码中我们使用Thickness结构来设置边距:

btnShow.Margin = new Thickness(,,,);

3.最大尺寸、最小尺寸

每个元素都提供Width和Height属性,用于显示的指定元素的大小,但有时候子元素的大小超过了父容器的大小时,我们就应当将子元素限制在正确的范围内,这个时候我们可以用MaxWidth和MaxWidth来进行设置,让我们来看下示例代码:

<Button MaxWidth="200" MaxHeight="100" Margin="40">Button 4</Button>

运行结果如下图:

WPF之旅(三)- 布局之StackPanel

从上图我们可以看到,Button4的默认的对齐方式为Stretch,Button4的宽度本来被拉伸至整个StackPanel的宽度,由于我们设置了MaxWidth,最后Button4实际的宽度被设置为200,这样子就达到了我们要调整合适宽度的目的。

上面就为我们今天说到的第一个布局控件(StackPanel),后续还会为大家梳理其他的布局控件。

本人最近开始学习WPF以及DevExpress,藉此提升自己C/S架构编程的能力。在学习过程会有一些心得体会,于是便会写一些博客来记录这些想法,有兴趣的朋友可以和我一起交流学习。那么就让我们从这里开始WPF与DevExpress的旅程吧!

QQ群: 32745894,欢迎大家加入讨论!