XAML学习笔记——Layout(二)
本篇随笔将简单介绍两种基本的布局——Grid布局和VariableSizedWrapGrid布局。
Grid布局
顾名思义,Grid布局将布局容器以行和列的分割方法拆分成若干单元格,然后通过指定子元素所属单元格的行编号(Grid.Row)与列编号(Grid.Column)的方式将一个或多个子元素排列在指定的单元格中,从而以表格的形式排列子元素。从功能和设计方式上讲,Grid布局排列子元素的行为和HTML中的 table 类似,但是使用方式更加灵活。Grid布局在开发过程中多用于表单的开发设计,并且经常用于其他布局的父容器嵌套使用,如以后会介绍的SplitView、ViewBox布局等。
定义行(Rows)和列(Columns)
依据定义,我们想要搞定Grid布局最重要的就是搞定行和列。具体来讲包括行和列的添加以及行和列尺寸的相关定义。
首先要根据需求确定Grid布局所需的行数与列数,Grid布局默认只包含一行一列,如果要添加其他的行和列就必须在Grid中的RowDefinitions
和ColumnDefinitions
两个属性集合中分别添加相应数量的子元素,下面的代码展示了如何定义一个包含四行两列的Grid。
1 <Grid> 2 <Grid.RowDefinitions> 3 <RowDefinition /> 4 <RowDefinition /> 5 <RowDefinition /> 6 <RowDefinition /> 7 </Grid.RowDefinitions> 8 <Grid.ColumnDefinitions> 9 <ColumnDefinition /> 10 <ColumnDefinition /> 11 </Grid.ColumnDefinitions> 12 </Grid>
确定好行和列的数量之后,我们就要为行和列的尺寸属性赋值。
在实际开发中我们关心的是行的高度(Height)属性和列的宽度(Width)属性,以行高为例,有三种方式可以为其赋值,分别为:
- Fixed 即此行高度为固定数值(据官方数据一个单位为1/96 英寸??)
- Auto 此行的高度完全取决于其包含元素的高度。
- Star (*) 按各行比例分配相应高度,举个例子就很容易明白了:
- 若将n行的高度都赋值为"*",那么每行的高度为n行所占总高度的1/n;
- 如果只有两行,第一行高度赋值为"3*"而第二行高度赋值为"5*",那么第一行就占两行总高度的3/8而第二行占5/8;
- 如果某些行的高度值以其他两种方式赋值,则不参与按比例赋值的计算;
用同样的方法为列的宽度属性赋值,接着上面的例子将行和列的尺寸赋值后,代码如下:
1 <Grid> 2 <Grid.RowDefinitions> 3 <RowDefinition Height="Auto" /> 4 <RowDefinition Height="Auto" /> 5 <RowDefinition Height="*" /> 6 <RowDefinition Height="28" /> 7 </Grid.RowDefinitions> 8 <Grid.ColumnDefinitions> 9 <ColumnDefinition Width="Auto" /> 10 <ColumnDefinition Width="200" /> 11 </Grid.ColumnDefinitions> 12 </Grid>
向Grid中添加元素
放在Grid中的元素必须放在<Grid>开闭标签之间,通过为元素添加Grid.Column和
Grid.Row
属性的方式来确定元素的位置,两个属性的值分别为Grid的列索引号和行索引号(从0开始)。
继续为上面的例子中添加几个控件,代码如下:
<Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> <RowDefinition Height="50" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="200" /> </Grid.ColumnDefinitions> <TextBlockGrid.Row="0" Grid.Column="0" Content="Name:"/> <TextBlockGrid.Row="1" Grid.Column="0" Content="E-Mail:"/> <TextBlock Grid.Row="2" Grid.Column="0" Content="Comment:"/> <TextBox Grid.Column="1" Grid.Row="0" Margin="3" /> <TextBox Grid.Column="1" Grid.Row="1" Margin="3" /> <TextBox Grid.Column="1" Grid.Row="2" Margin="3" /> <Button Grid.Column="1" Grid.Row="3" HorizontalAlignment="Right" MinWidth="80" Margin="3" Content="Send" /> </Grid>
要想继续调整元素在单元格内的位置,可以通过上篇随笔中介绍的HorizontalAlignment、VerticalAlignment和Margin三个属性来实现,抄袭一张图片:
调整之后示例代码的运行结果如下:
在code中实现Grid
用xaml实现Grid布局虽然可以将行和列的定义与应用分开,但是代码十分冗长写起来真的是很痛苦,每一行和列都需要手动添加,尤其是行和列的定义部分显得很长。如果在实际开发中遇到相对复杂表单时,可以考虑在code中应用for循环来搞定。
在code中可以通过GridLength
类实现行和列的尺寸属性定义,三种定义的code实现方式如下:
Auto |
|
Star |
|
Fixed |
|
给个简单的实例代码:
1 Grid grid = new Grid(); 2 3 ColumnDefinition col1 = new ColumnDefinition(); 4 col1.Width = GridLength.Auto; 5 ColumnDefinition col2 = new ColumnDefinition(); 6 col2.Width = new GridLength(1,GridUnitType.Star); 7 8 grid.ColumnDefinitions.Add(col1); 9 grid.ColumnDefinitions.Add(col2);
以上就是关于Grid布局的简介。
VariableSizedWrapGrid布局
和上面介绍的Grid布局一样, VariableSizedWrapGrid 也是将布局容器按照行和列平均分割成若干单元格,并将所有的子元素排列其中。不同点在于VariableSizedWrapGrid的行和列数量是可变的。换一种理解方式,其本质就是最简单的布局方式——“流式布局”,只不过借用grid的展现方式而已。用流式布局的理解方式就很容易明白搞定VariableSizedWrapGrid布局的关键在于两点——确定子元素的“流动方向”(Orientation)和子元素“流动范围”(MaximumRowsOrColumns )。
确定元素“流动方向”
通过Orientation属性可以控制元素的排列方向。当赋值为Vertical时,元素按照竖直方向从左到右排列。此属性的默认值即为Vertical。
给个例子:
1 <VariableSizedWrapGrid Orientation="Vertical" Margin="20"> 2 3 <VariableSizedWrapGrid.Resources> 4 <Style TargetType="Button"> 5 <Setter Property="Background" 6 Value="LightBlue"/> 7 <Setter Property="Margin" 8 Value="20"/> 9 <Setter Property="Padding" 10 Value="10"/> 11 </Style> 12 </VariableSizedWrapGrid.Resources> 13 14 <Button Content="Button1"/> 15 <Button Content="Button2"/> 16 <Button Content="Button3"/> 17 <Button Content="Button4"/> 18 <Button Content="Button5"/> 19 <Button Content="Button6"/> 20 <Button Content="Button7"/> 21 <Button Content="Button8"/> 22 <Button Content="Button9"/> 23 <Button Content="Button0"/> 24 25 </VariableSizedWrapGrid>
效果图如下:
若将Orientation属性改为Horizontal,则元素按照水平方向从左至右排列,效果:
这个属性实在是很好理解,和其他“流式布局”相同,当窗口缩放时,元素的排列的行数和列数也会随之出现相应的变化。如果想要限定元素排列的行数或者列数就要用到MaximumRowsOrColumns属性了。
确定元素“流动范围”
通过对MaximumRowsOrColumns属性赋值可以限定元素的排列范围,但是这个属性的实际含义却取决于Orientation属性的值,借用上面的例子,当元素按竖直方向排列,并且为MaximumRowsOrColumns属性赋值“2”时:
1 <VariableSizedWrapGrid Margin="20" Orientation="Vertical" MaximumRowsOrColumns="2"> 2 ...... 3 4 </VariableSizedWrapGrid>
效果如下:
结果所有Button整齐的排列成两行,并且位置固定,不随着窗口的缩放改变位置。可见当Orientation="Vertical"时,MaximumRowsOrColumns约束的是元素排列的最大“行数”。如果把元素的排列方向改为水平,其他不变:
1 <VariableSizedWrapGrid Margin="20" Orientation="Horizontal" MaximumRowsOrColumns="2">
2 ......
3
4 </VariableSizedWrapGrid>
则变为:
则结果所有Button整齐的排列成两列,位置依然固定。由此可见当Orientation="Horizontal"时,MaximumRowsOrColumns约束的是元素排列的最大“列数”。
虽然结果明了,但是过程比较费解。。为什么不把行和列分开约束呢??网上有关此布局的先关资料实在有限,本人也是通过实战方式得出结论,专业性肯定差点,如果查到相关资料我会第一时间修正。总之,有待继续学习。。好吧,暂时会用就行。。
跨单元格排列元素
以上例子中的元素都是按照单个单元格进行排列,我们也可以使用VariableSizedWrapGrid.ColumnSpan和VariableSizedWrapGrid.RowSpan两个属性使元素跨单元格排列。举一个极简单的例子,将上面例子中的Button1和Button2修改如下:
<Button VariableSizedWrapGrid.RowSpan="2" Content="Button1"/> <Button VariableSizedWrapGrid.ColumnSpan="2" Content="Button2"/>
效果如下:
这两个布局的基本用法先介绍到这里。。一篇随笔介绍两个布局貌似篇幅有点大。。下篇随笔准备介绍两种简单的布局——StackPanel和RelativePanel。