2.1 Grid面板布局

Grid面板是Windows phoneMango应用程序页面布局中,使用最广泛的面板。Grid面板类似于HTML网页设计中的表格Table,即通过将整个页面划分成由多个行和列组成的单元格,将元素放置于单元格中实现布局。因此,如果以前熟悉HTML设计,就比较容易理解和使用Grid。

2.1.1 定义行与列

使用Grid 面板进行页面布局,首先需要在Grid面板中划分行和列。定义行和列的XAML代码分别是RowDefinition和ColumnDefinition,例如,以下代码将Grid划分成3行两列,在模拟器预览窗口中显示的效果如图2-1所示。

XAML代码:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
          <Grid.ColumnDefinitions>
              <ColumnDefinition />
              <ColumnDefinition />
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
              <RowDefinition />
              <RowDefinition />
              <RowDefinition />
          </Grid.RowDefinitions>
</Grid>

图2-1 Grid行和列的定义

即,行的定义是在<Grid.RowDefinitions>标记中添加<RowDefinition/>标记,列的定义是在<Grid.ColumnDefinitions>标记中添加<ColumnDefinition/>标记。

行与列的大小,即单元格大小,可以通过设置<RowDefinition/>的高度值属性Height与<ColumnDefinition/>的宽度值属性Width来实现。如以下代码定义了两列的宽度分别是100和200,三行的高度分别100、200和300。

XAML代码:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
           <Grid.ColumnDefinitions>
              <ColumnDefinition Width="100"/>
              <ColumnDefinition Width="200"/>
           </Grid.ColumnDefinitions>
           <Grid.RowDefinitions>
              <RowDefinition Height="100"/>
              <RowDefinition Height="200"/>
              <RowDefinition Height="300"/>
           </Grid.RowDefinitions>
</Grid>

这种直接以确定数值指定行(或列)的高度(或宽度)的方式,被称为绝对尺寸(Absolute Sizing)设置方式,相对简单明了。但是在实际使用过程中,这些绝对尺寸值是固定的,无法适应屏幕方向的变化和在元素增减时要求布局自动调整的需要。为了解决这方面的问题,Silverlight for Windows phoneMango还提供了自动尺寸(Autosizing)和比例尺寸(Proportional Sizing),比例尺寸还被称为星号尺寸(Star Sizing)。这3种尺寸设置方式的特点如下。

1.绝对尺寸

绝对尺寸使用确定的数值来定义行或列的大小,这些值不会因为Grid面板所占空间大小的变化而变化。

2.自动尺寸

自动尺寸将Width和Height值设为Auto,如Width="Auto"或Height="Auto",当元素放置于单元格时,行与列的Height与Width值将由单元格中子元素的大小确定。但是,当一行或一列中有多个单元格,并放置多个子元素时,行与列的Height与Width的实际值由每一行与每一列中最大Height值与Width值决定。相比绝对尺寸,自动尺寸更具灵活性,尤其是更能适应单元格内容的动态变化,两者的区别如图2-2所示。

图2-2 绝对尺寸与自动尺寸的比较

显示图2-2的代码如下。

XAML代码:Gridpanel1.xaml

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" ShowGridLines="True">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="200"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="300"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Button Content="宽200,高300" Height="72" Margin="12" Name="Button1" VerticalAlignment="Center" HorizontalAlignment="Stretch" />
            <Button Content="自动尺寸,宽高都为Auto" Height="72" Margin="12" Name="Button2" VerticalAlignment="Center" HorizontalAlignment="Stretch" Grid.Row="0" Grid.Column="1"/>
</Grid>

从代码可见,第一行与第一列的高度与宽度设置为绝对尺寸,分别为Width="200"和Height="300",第二行与第二列的宽度与高度设置为自动尺寸;在第一行第一列的单元格中放置一个Button1,这个Button1显示的内容为“宽200,高300”,但是由于单元格是绝对尺寸且宽度不足,Button1的内容没有全部显示出来。第一行第二列的单元格中放置Button2,由于单元格的宽度为自动尺寸,因此,单元格的宽度根据Button2内容的宽度做了自动调整,Button2的内容全部显示出来了。

3.比例尺寸

比例尺寸使用系数和星号(*)的组合来表示尺寸大小,如Width="2.5*",这样系统会自动根据系数的比例来分配尺寸。这种分配方法跟行与列设置值的情况有关,具体分为以下3种情况。

  • 只有一行的高度或一列宽度被设置为“*”时,该行或列会占据剩余的高度或宽度。
  • 有多行的高度或多列的宽度设置为“*”时,这些行或列平分剩余的高度或宽度。
  • 多行的高度或多列的宽度设置为系数与“*”的组合时,这些行或列按系数比例分配尺寸。如行1的Height="3.5*",行2的Height="1.5*",则行1的Height占可分配空间的70%,行2的Height占30%。其中Height="*"等同于Height="1*"。

图2-3所示可以说明上述3种情况。Grid1中,第一列的宽度Width="180",为绝对尺寸,第二列为Width="*",为比例尺寸,则第一列宽度固定,第二列占据剩余宽度。Grid2中,第一列宽度为绝对尺寸,宽度值固定,其他列宽都为"*",平分剩余宽度。Grid3和Grid4除第一列为固定尺寸外,其余列按比例分配剩余宽度。

图2-3 比例尺寸的空间分配

行与列的定义与尺寸设置除了可以在XAML代码中实现之外,还可以通过程序代码来实现,如以下代码创建了一个三行,三列的Grid,并对行与列的尺寸进行了设置。程序运行的结果如图2-4所示。

XAML代码:Gridpanel2.xaml.vb

Dim Grid1 As Grid=New Grid
Dim row As RowDefinition
Dim col As ColumnDefinition
Dim i As Integer=0
For i=1 To 3
   row=New RowDefinition
   row.Height=New GridLength(30 * i,GridUnitType.Pixel)
   Grid1.RowDefinitions.Add(row)
Next
For i=1 To 3
   col=New ColumnDefinition
   col.Width=New GridLength(i,GridUnitType.Star)
   Grid1.ColumnDefinitions.Add(col)
Next
Grid1.ShowGridLines=True
Grid1.Margin=New Thickness(20)
Grid1.Height=180
Grid1.Width=300
Grid.SetRow(Grid1,1)
Me.LayoutRoot.Children.Add(Grid1)

图2-4 程序代码定义Grid行与列

其中,GridUnitType是个枚举类,可选的值有Pixel、Star、Auto;分别表示尺寸设置方式为绝对尺寸、比例尺寸和自动尺寸。在设计阶段,为了便于观察单元格,可以将Grid面板控件的ShowGridLines属性设置为True,表示显示表格线,表格线会以虚线形式显示。

提示:

Grid行与列的划分和尺寸也可以在模拟器预览窗口中进行划分。

2.1.2 设置子元素的位置

定义Grid面板的行和列之后,就可以将子元素布置到单元格中。定义子元素在单元格的位置,可以采用附加属性Grid.Row和Grid.Column。如在实例图2-2对应的代码中,对Button2设置了Grid.Row="0"和Grid.Column="1",即表示将元素Button2放置于第一行、第二列中。Grid的行与列编号是从0开始编的,因此Grid.Row="0"表示第一行,Grid.Row="1"表示第二行。而Button1未设置Grid.Row和Grid.Column表示取默认值,Grid.Row和Grid.Column的默认值都是0,因此,Button1实际是放置在第一行第一列的单元格。

Grid的单元格可以放置的子元素不止一个,当有多个子元素置于同一个单元格中时,这些元素可能会出现重叠。在代码顺序中排在后面的元素会叠加在顺序靠前的元素之上。如以下代码表示在Grid的第一行第一列放置两个Button,其中,Button2叠加在Button1之上,如图2-5所示。

XAML代码:Gridpanel3.xaml

<Button Name="Button1" Width="200" Height="120" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="0" Grid.Column="0">Button1</Button>
<Button Name="Button2" Width="200" Height="120" Background="#FFDEA0A0" Grid.Row="0" Grid.Column="0" >Button2</Button>

图2-5 多个元素置于同一单元格时出现重叠

这种同一单元格中重叠的特性,有时候比较有用。如Silverlight for Windows Phone默认提供了多个图标,但有些图标可能没有。如图2-6所示,采用两个图标在同一单元格中重叠的特性,构造出了一个新图标。

图2-6 利用叠加构造新图标

代码如下。

XAML代码:

<Image Source="/Images/appbar.basecircle.rest.png" Width="48" Height="48" Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center" />
<Image Source="/Images/appbar.add.rest.png" Width="48" Height="48" Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center" />

子元素可以放置在Grid面板的一个单元格中,也可以跨越多行或者多列,这可以使用Grid.RowSpan和Grid.ColumnSpan进行设置。如Grid.RowSpan=2表示跨越两行,可以使用两的空间,Grid.ColumnSpan=3,表示跨越三列。Grid.RowSpan和Grid.ColumnSpan的默认值都为1,表示置于一行和一列内。

如以下代码表示Button2置于第二行,第一列,但跨越二列,如图2-7所示。

XAML代码:

<Button Name="Button3" Width="400" Background="#FFDEA0A0" Grid.Row="1" Grid.ColumnSpan="2" Margin="28,14,28,1">Button2</Button>

提示:

在程序代码中使用上述附加属性,可以采用如下方式。

VBnet代码:

Dim button As New Button
Grid.SetRow(button,1)
Grid.SetColumn(button,1)

图2-7 元素跨越多列