Xamarin.Forms 网格

Xamarin.Forms 网格

Grid 是一种布局,它将其子级组织为行和列,这些行和列可以具有比例或绝对大小。 默认情况下,Grid 包含一行和一列。 此外,Grid 还可用作包含其他子布局的父布局。

Grid 布局不应与表混淆,并且不应显示表格数据。 与 HTML 表不同,Grid 用于布局内容。 若要显示表格数据,请考虑使用 ListViewCollectionView TableView

Grid 类定义以下属性:

  • Column,类型为 int,是一个附加属性,用于指示父 Grid 中视图的列对齐方式。 此属性的默认值为 0。 验证回调可确保在设置属性时,其值大于或等于 0。
  • ColumnDefinitions,类型为 ColumnDefinitionCollection,是定义网格列宽度的 ColumnDefinition 对象的列表。
  • ColumnSpacing,类型为 double,表示网格列之间的距离。 此属性的默认值为 6 个独立于设备的单位。
  • ColumnSpan,类型为 int,是一个附加属性,用于指示视图在父级 Grid 中跨越的总列数。 此属性的默认值为 1。 验证回调可确保设置属性时,其值大于或等于 1。
  • Row,类型为 int,是一个附加属性,用于指示父级 Grid 中视图的行对齐方式。 此属性的默认值为 0。 验证回调可确保在设置属性时,其值大于或等于 0。
  • RowDefinitions,类型为 RowDefinitionCollection,是定义网格行高度的 RowDefintion 对象列表。
  • RowSpacing,类型为 double,指示网格行之间的距离。 此属性的默认值为 6 个独立于设备的单位。
  • RowSpan,类型为 int,是一个附加属性,用于指示视图在父级 Grid 中跨越的总行数。 此属性的默认值为 1。 验证回调可确保设置属性时,其值大于或等于 1。

这些属性由 BindableProperty 对象提供支持,这意味着它们可以作为数据绑定的目标,也可以进行设置样式。

Grid 类派生自 Layout<T> 类,后者定义了类型 IList<T>Children 属性。 由于 Children 属性是 Layout<T> 类的 ContentProperty,因此不需要通过 XAML 显式设置。

提示

若要获取最佳可能布局性能,请遵循优化布局性能中的准则。

行和列

默认情况下,Grid 包含一行和一列:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="GridTutorial.MainPage">
    <Grid Margin="20,35,20,20">
        <Label Text="By default, a Grid contains one row and one column." />
    </Grid>
</ContentPage>

在此示例中,Grid 包含一个自动定位在单个位置的子级 Label

默认网格布局的屏幕截图

可以使用 RowDefinitionsColumnDefinitions 属性定义 Grid 的布局行为,这两个属性分别是 RowDefinitionColumnDefinition 对象的集合。 这些集合定义 Grid 的行和列特征,并且应针对 Grid 中的每一行包含一个 RowDefinition 对象,针对 Grid 中的每一列包含一个 ColumnDefinition 对象。

RowDefinition 类定义类型为 GridLengthHeight 属性,而 ColumnDefinition 类定义类型为 GridLengthWidth 属性。 GridLength 结构根据 GridUnitType 枚举指定行高或列宽,该枚举具有三个成员:

  • Absolute – 行高或列宽是以设备无关单位表示的值(XAML 中的数字)。
  • Auto – 根据单元格内容自动调整行高或列宽(在 XAML 中为 Auto)。
  • Star – 按比例分配剩余行高或列宽(在 XAML 中,是后跟 * 的数字)。

Height 属性为 AutoGrid 行可约束该行中视图的高度,所用方式与垂直 StackLayout 相同。 同样,Width 属性为 Auto 的列的工作方式与水平 StackLayout 非常相似。

注意

尽量确保将尽可能少的行和列设置为 Auto 大小。 每个自动调整大小的行或列都会导致布局引擎执行额外布局计算。 应在可能时使用固定大小的行和列。 或者,将行和列设置为使用 GridUnitType.Star 枚举值按比例占用空间量。

以下 XAML 展示了如何创建具有三行和两列的 Grid

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="GridDemos.Views.BasicGridPage"
             Title="Basic Grid demo">
   <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="2*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="100" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        ...
    </Grid>
</ContentPage>

在此示例中,Grid 的总高度是页面的高度。 Grid 知道第三行的高度为 100 个设备无关单位。 它从自身高度中减去该高度,并根据星号前面的数字在第一行和第二行之间按比例分配剩余高度。 在此示例中,第一行的高度是第二行高度的两倍。

两个 ColumnDefinition 对象都将 Width 设置为 *,这与 1* 相同,意味着两列下方的屏幕宽度相等。

重要说明

RowDefinition.Height 属性的默认值为 *。 同样,ColumnDefinition.Width 属性的默认值为 *。 因此,在可以接受这些默认值的情况下,无需设置这些属性。

可以将子视图放置在包含 Grid.ColumnGrid.Row 附加属性的特定 Grid 单元格中。 此外,要使子视图跨越多个行和列,请使用 Grid.RowSpanGrid.ColumnSpan 附加属性。

以下 XAML 显示相同的 Grid 定义,并将子视图定位在特定 Grid 单元格中:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="GridDemos.Views.BasicGridPage"
             Title="Basic Grid demo">
   <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="2*" />
            <RowDefinition />
            <RowDefinition Height="100" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <BoxView Color="Green" />
        <Label Text="Row 0, Column 0"
               HorizontalOptions="Center"
               VerticalOptions="Center" />
        <BoxView Grid.Column="1"
                 Color="Blue" />
        <Label Grid.Column="1"
               Text="Row 0, Column 1"
               HorizontalOptions="Center"
               VerticalOptions="Center" />
        <BoxView Grid.Row="1"
                 Color="Teal" />
        <Label Grid.Row="1"
               Text="Row 1, Column 0"
               HorizontalOptions="Center"
               VerticalOptions="Center" />
        <BoxView Grid.Row="1"
                 Grid.Column="1"
                 Color="Purple" />
        <Label Grid.Row="1"
               Grid.Column="1"
               Text="Row1, Column 1"
               HorizontalOptions="Center"
               VerticalOptions="Center" />
        <BoxView Grid.Row="2"
                 Grid.ColumnSpan="2"
                 Color="Red" />
        <Label Grid.Row="2"
               Grid.ColumnSpan="2"
               Text="Row 2, Columns 0 and 1"
               HorizontalOptions="Center"
               VerticalOptions="Center" />
    </Grid>
</ContentPage>

注意

Grid.RowGrid.Column 属性均从 0 开始索引,因此 Grid.Row="2" 指示第三行,而 Grid.Column="1" 指示第二列。 此外,这两个属性的默认值均为 0,因此无需在占用 Grid 的第一行或第一列的子视图上设置此属性。

在此示例中,所有三个 Grid 行均被 BoxViewLabel 视图占用。 第三行高 100 个与设备无关的单位,其中前两行占用剩余空间(第一行高是第二行的两倍)。 两列同宽,并将 Grid 分成两半。 第三行的 BoxView 跨越这两列。

基本网格布局的屏幕截图

此外,Grid 中的子视图还可以共享单元格。 子级在 XAML 中的显示顺序是子级在 Grid 中的放置顺序。 在前面的示例中,之所以只能显示 Label 对象,是因为它们呈现在 BoxView 对象之上。 如果 BoxView 对象呈现在 Label 对象之上,则后者将不可见。

等效 C# 代码如下:

public class BasicGridPageCS : ContentPage
{
    public BasicGridPageCS()
    {
        Grid grid = new Grid
        {
            RowDefinitions =
            {
                new RowDefinition { Height = new GridLength(2, GridUnitType.Star) },
                new RowDefinition(),
                new RowDefinition { Height = new GridLength(100) }
            },
            ColumnDefinitions =
            {
                new ColumnDefinition(),
                new ColumnDefinition()
            }
        };

        // Row 0
        // The BoxView and Label are in row 0 and column 0, and so only needs to be added to the
        // Grid.Children collection to get default row and column settings.
        grid.Children.Add(new BoxView
        {
            Color = Color.Green
        });
        grid.Children.Add(new Label
        {
            Text = "Row 0, Column 0",
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.Center
        });

        // This BoxView and Label are in row 0 and column 1, which are specified as arguments
        // to the Add method.
        grid.Children.Add(new BoxView
        {
            Color = Color.Blue
        }, 1, 0);
        grid.Children.Add(new Label
        {
            Text = "Row 0, Column 1",
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.Center
        }, 1, 0);

        // Row 1
        // This BoxView and Label are in row 1 and column 0, which are specified as arguments
        // to the Add method overload.
        grid.Children.Add(new BoxView
        {
            Color = Color.Teal
        }, 0, 1, 1, 2);
        grid.Children.Add(new Label
        {
            Text = "Row 1, Column 0",
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.Center
        }, 0, 1, 1, 2); // These arguments indicate that that the child element goes in the column starting at 0 but ending before 1.
                        // They also indicate that the child element goes in the row starting at 1 but ending before 2.

        grid.Children.Add(new BoxView
        {
            Color = Color.Purple
        }, 1, 2, 1, 2);
        grid.Children.Add(new Label
        {
            Text = "Row1, Column 1",
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.Center
        }, 1, 2, 1, 2);

        // Row 2
        // Alternatively, the BoxView and Label can be positioned in cells with the Grid.SetRow
        // and Grid.SetColumn methods.
        BoxView boxView = new BoxView { Color = Color.Red };
        Grid.SetRow(boxView, 2);
        Grid.SetColumnSpan(boxView, 2);
        Label label = new Label
        {
            Text = "Row 2, Column 0 and 1",
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.Center
        };
        Grid.SetRow(label, 2);
        Grid.SetColumnSpan(label, 2);

        grid.Children.Add(boxView);
        grid.Children.Add(label);

        Title = "Basic Grid demo";
        Content = grid;
    }
}

在代码中,要指定 RowDefinition 对象的高度和 ColumnDefinition 对象的宽度,请使用 GridLength 结构的值,通常与 GridUnitType 枚举结合使用。

上面的示例代码还显示了几种不同方法,用于将子级添加到 Grid 并指定它们所在的单元格。 使用指定顶部底部参数的 Add 重载时,顶部参数将始终引用 Grid 中的单元格,而底部参数似乎会引用 Grid 之外的单元格。 这是因为参数必须始终大于参数,而底部参数必须始终大于顶部参数。 以下示例假定为 2x2 Grid,它使用两个 Add 重载显示等效代码:

// left, top
grid.Children.Add(topLeft, 0, 0);           // first column, first row
grid.Children.Add(topRight, 1, 0);          // second column, first tow
grid.Children.Add(bottomLeft, 0, 1);        // first column, second row
grid.Children.Add(bottomRight, 1, 1);       // second column, second row

// left, right, top, bottom
grid.Children.Add(topLeft, 0, 1, 0, 1);     // first column, first row
grid.Children.Add(topRight, 1, 2, 0, 1);    // second column, first tow
grid.Children.Add(bottomLeft, 0, 1, 1, 2);  // first column, second row
grid.Children.Add(bottomRight, 1, 2, 1, 2); // second column, second row

注意

此外,可以使用 AddHorizontalAddVertical 方法将子视图添加到 Grid ,从而将子视图添加到单行或单列 Grid。 然后,Grid 在进行这些调用时在行或列中展开,并自动将子级定位到正确的单元格中。

简化行和列定义

在 XAML 中,可以使用简化的语法指定 Grid 的行和列特征,这样就不必为每行和每列定义 RowDefinitionColumnDefinition 对象。 相反,可以将 RowDefinitionsColumnDefinitions 属性设置为包含逗号分隔 GridUnitType 值的字符串,其中在 Xamarin.Forms 中生成的类型转换器会创建 RowDefinitionColumnDefinition 对象:

<Grid RowDefinitions="1*, Auto, 25, 14, 20"
      ColumnDefinitions="*, 2*, Auto, 300">
    ...
</Grid>

在此示例中,Grid 有五行和四列。 第三行、第四行和第五行设置为绝对高度,第二行根据其内容自动调整大小。 然后将剩余高度分配给第一行。

第四列设置为绝对宽度,第三列根据其内容自动调整大小。 剩余宽度根据星号前的数字在第一列和第二列之间按比例分配。 在此示例中,第二列的宽度是第一列的两倍(因为 *1* 相同)。

行和列之间的间距

默认情况下,Grid 行由 6 个独立于设备的空间单位分隔。 同样,Grid 列由 6 个独立于设备的空间单位分隔。 可以通过分别设置 RowSpacingColumnSpacing 属性来更改这些默认值:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="GridDemos.Views.GridSpacingPage"
             Title="Grid spacing demo">
    <Grid RowSpacing="0"
          ColumnSpacing="0">
        ..
    </Grid>
</ContentPage>

此示例创建在其行和列之间没有间距的 Grid

单元格之间没有间距的网格的屏幕截图

提示

可以将 RowSpacingColumnSpacing 属性设置为负值,以使单元格内容重叠。

等效 C# 代码如下:

public GridSpacingPageCS()
{
    Grid grid = new Grid
    {
        RowSpacing = 0,
        ColumnSpacing = 0,
        // ...
    };
    // ...

    Content = grid;
}

对齐

可以通过 HorizontalOptionsVerticalOptions 属性将 Grid 中的子视图定位在其单元格中。 这些属性可以设置为 LayoutOptions 结构中的以下字段:

重要

LayoutOptions 结构中的 AndExpands 字段仅适用于 StackLayout 对象。

以下 XAML 创建包含九个大小相等的单元格的 Grid,并在每个单元格中放置一个以不同方式对齐的 Label

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="GridDemos.Views.GridAlignmentPage"
             Title="Grid alignment demo">
    <Grid RowSpacing="0"
          ColumnSpacing="0">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <BoxView Color="AliceBlue" />
        <Label Text="Upper left"
               HorizontalOptions="Start"
               VerticalOptions="Start" />
        <BoxView Grid.Column="1"
                 Color="LightSkyBlue" />
        <Label Grid.Column="1"
               Text="Upper center"
               HorizontalOptions="Center"
               VerticalOptions="Start"/>
        <BoxView Grid.Column="2"
                 Color="CadetBlue" />
        <Label Grid.Column="2"
               Text="Upper right"
               HorizontalOptions="End"
               VerticalOptions="Start" />
        <BoxView Grid.Row="1"
                 Color="CornflowerBlue" />
        <Label Grid.Row="1"
               Text="Center left"
               HorizontalOptions="Start"
               VerticalOptions="Center" />
        <BoxView Grid.Row="1"
                 Grid.Column="1"
                 Color="DodgerBlue" />
        <Label Grid.Row="1"
               Grid.Column="1"
               Text="Center center"
               HorizontalOptions="Center"
               VerticalOptions="Center" />
        <BoxView Grid.Row="1"
                 Grid.Column="2"
                 Color="DarkSlateBlue" />
        <Label Grid.Row="1"
               Grid.Column="2"
               Text="Center right"
               HorizontalOptions="End"
               VerticalOptions="Center" />
        <BoxView Grid.Row="2"
                 Color="SteelBlue" />
        <Label Grid.Row="2"
               Text="Lower left"
               HorizontalOptions="Start"
               VerticalOptions="End" />
        <BoxView Grid.Row="2"
                 Grid.Column="1"
                 Color="LightBlue" />
        <Label Grid.Row="2"
               Grid.Column="1"
               Text="Lower center"
               HorizontalOptions="Center"
               VerticalOptions="End" />
        <BoxView Grid.Row="2"
                 Grid.Column="2"
                 Color="BlueViolet" />
        <Label Grid.Row="2"
               Grid.Column="2"
               Text="Lower right"
               HorizontalOptions="End"
               VerticalOptions="End" />
    </Grid>
</ContentPage>

在此示例中,每行中的 Label 对象在垂直方向上的对齐方式完全相同,但使用不同的水平对齐方式。 或者,可以将其视为每列中的 Label 对象在水平方向上的对齐方式完全相同,但使用不同的垂直对齐方式:

网格中单元格对齐的屏幕截图

等效 C# 代码如下:

public class GridAlignmentPageCS : ContentPage
{
    public GridAlignmentPageCS()
    {
        Grid grid = new Grid
        {
            RowSpacing = 0,
            ColumnSpacing = 0,
            RowDefinitions =
            {
                new RowDefinition(),
                new RowDefinition(),
                new RowDefinition()
            },
            ColumnDefinitions =
            {
                new ColumnDefinition(),
                new ColumnDefinition(),
                new ColumnDefinition()
            }
        };

        // Row 0
        grid.Children.Add(new BoxView
        {
            Color = Color.AliceBlue
        });
        grid.Children.Add(new Label
        {
            Text = "Upper left",
            HorizontalOptions = LayoutOptions.Start,
            VerticalOptions = LayoutOptions.Start
        });

        grid.Children.Add(new BoxView
        {
            Color = Color.LightSkyBlue
        }, 1, 0);
        grid.Children.Add(new Label
        {
            Text = "Upper center",
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.Start
        }, 1, 0);

        grid.Children.Add(new BoxView
        {
            Color = Color.CadetBlue
        }, 2, 0);
        grid.Children.Add(new Label
        {
            Text = "Upper right",
            HorizontalOptions = LayoutOptions.End,
            VerticalOptions = LayoutOptions.Start
        }, 2, 0);

        // Row 1
        grid.Children.Add(new BoxView
        {
            Color = Color.CornflowerBlue
        }, 0, 1);
        grid.Children.Add(new Label
        {
            Text = "Center left",
            HorizontalOptions = LayoutOptions.Start,
            VerticalOptions = LayoutOptions.Center
        }, 0, 1);

        grid.Children.Add(new BoxView
        {
            Color = Color.DodgerBlue
        }, 1, 1);
        grid.Children.Add(new Label
        {
            Text = "Center center",
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.Center
        }, 1, 1);

        grid.Children.Add(new BoxView
        {
            Color = Color.DarkSlateBlue
        }, 2, 1);
        grid.Children.Add(new Label
        {
            Text = "Center right",
            HorizontalOptions = LayoutOptions.End,
            VerticalOptions = LayoutOptions.Center
        }, 2, 1);

        // Row 2
        grid.Children.Add(new BoxView
        {
            Color = Color.SteelBlue
        }, 0, 2);
        grid.Children.Add(new Label
        {
            Text = "Lower left",
            HorizontalOptions = LayoutOptions.Start,
            VerticalOptions = LayoutOptions.End
        }, 0, 2);

        grid.Children.Add(new BoxView
        {
            Color = Color.LightBlue
        }, 1, 2);
        grid.Children.Add(new Label
        {
            Text = "Lower center",
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.End
        }, 1, 2);

        grid.Children.Add(new BoxView
        {
            Color = Color.BlueViolet
        }, 2, 2);
        grid.Children.Add(new Label
        {
            Text = "Lower right",
            HorizontalOptions = LayoutOptions.End,
            VerticalOptions = LayoutOptions.End
        }, 2, 2);

        Title = "Grid alignment demo";
        Content = grid;
    }
}

嵌套网格对象

Grid 可用作包含嵌套子 Grid 对象或其他子布局的父布局。 嵌套 Grid 对象时,Grid.RowGrid.ColumnGrid.RowSpanGrid.ColumnSpan 附加属性始终引用视图在其父 Grid 中的位置。

以下 XAML 展示了一个嵌套 Grid 对象的示例:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:converters="clr-namespace:GridDemos.Converters"
             x:Class="GridDemos.Views.ColorSlidersGridPage"
             Title="Nested Grids demo">

    <ContentPage.Resources>
        <converters:DoubleToIntConverter x:Key="doubleToInt" />

        <Style TargetType="Label">
            <Setter Property="HorizontalTextAlignment"
                    Value="Center" />
        </Style>
    </ContentPage.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <BoxView x:Name="boxView"
                 Color="Black" />
        <Grid Grid.Row="1"
              Margin="20">
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
            <Slider x:Name="redSlider"
                    ValueChanged="OnSliderValueChanged" />
            <Label Grid.Row="1"
                   Text="{Binding Source={x:Reference redSlider},
                                  Path=Value,
                                  Converter={StaticResource doubleToInt},
                                  ConverterParameter=255,
                                  StringFormat='Red = {0}'}" />
            <Slider x:Name="greenSlider"
                    Grid.Row="2"
                    ValueChanged="OnSliderValueChanged" />
            <Label Grid.Row="3"
                   Text="{Binding Source={x:Reference greenSlider},
                                  Path=Value,
                                  Converter={StaticResource doubleToInt},
                                  ConverterParameter=255,
                                  StringFormat='Green = {0}'}" />
            <Slider x:Name="blueSlider"
                    Grid.Row="4"
                    ValueChanged="OnSliderValueChanged" />
            <Label Grid.Row="5"
                   Text="{Binding Source={x:Reference blueSlider},
                                  Path=Value,
                                  Converter={StaticResource doubleToInt},
                                  ConverterParameter=255,
                                  StringFormat='Blue = {0}'}" />
        </Grid>
    </Grid>
</ContentPage>

在此示例中,根 Grid 布局在其第一行中包含 BoxView,而在其第二行中包含一个子元素 Grid。 子 Grid 包含 Slider 对象,用于调整 BoxView 显示的颜色,以及 Label 对象,用于显示每个 Slider 的值:

嵌套网格的屏幕截图

重要

嵌套 Grid 对象和其他布局越深,嵌套布局对性能的影响就越大。 有关详细信息,请参阅选择正确的布局

等效 C# 代码如下:

public class ColorSlidersGridPageCS : ContentPage
{
    BoxView boxView;
    Slider redSlider;
    Slider greenSlider;
    Slider blueSlider;

    public ColorSlidersGridPageCS()
    {
        // Create an implicit style for the Labels
        Style labelStyle = new Style(typeof(Label))
        {
            Setters =
            {
                new Setter { Property = Label.HorizontalTextAlignmentProperty, Value = TextAlignment.Center }
            }
        };
        Resources.Add(labelStyle);

        // Root page layout
        Grid rootGrid = new Grid
        {
            RowDefinitions =
            {
                new RowDefinition(),
                new RowDefinition()
            }
        };

        boxView = new BoxView { Color = Color.Black };
        rootGrid.Children.Add(boxView);

        // Child page layout
        Grid childGrid = new Grid
        {
            Margin = new Thickness(20),
            RowDefinitions =
            {
                new RowDefinition(),
                new RowDefinition(),
                new RowDefinition(),
                new RowDefinition(),
                new RowDefinition(),
                new RowDefinition()
            }
        };

        DoubleToIntConverter doubleToInt = new DoubleToIntConverter();

        redSlider = new Slider();
        redSlider.ValueChanged += OnSliderValueChanged;
        childGrid.Children.Add(redSlider);

        Label redLabel = new Label();
        redLabel.SetBinding(Label.TextProperty, new Binding("Value", converter: doubleToInt, converterParameter: "255", stringFormat: "Red = {0}", source: redSlider));
        Grid.SetRow(redLabel, 1);
        childGrid.Children.Add(redLabel);

        greenSlider = new Slider();
        greenSlider.ValueChanged += OnSliderValueChanged;
        Grid.SetRow(greenSlider, 2);
        childGrid.Children.Add(greenSlider);

        Label greenLabel = new Label();
        greenLabel.SetBinding(Label.TextProperty, new Binding("Value", converter: doubleToInt, converterParameter: "255", stringFormat: "Green = {0}", source: greenSlider));
        Grid.SetRow(greenLabel, 3);
        childGrid.Children.Add(greenLabel);

        blueSlider = new Slider();
        blueSlider.ValueChanged += OnSliderValueChanged;
        Grid.SetRow(blueSlider, 4);
        childGrid.Children.Add(blueSlider);

        Label blueLabel = new Label();
        blueLabel.SetBinding(Label.TextProperty, new Binding("Value", converter: doubleToInt, converterParameter: "255", stringFormat: "Blue = {0}", source: blueSlider));
        Grid.SetRow(blueLabel, 5);
        childGrid.Children.Add(blueLabel);

        // Place the child Grid in the root Grid
        rootGrid.Children.Add(childGrid, 0, 1);

        Title = "Nested Grids demo";
        Content = rootGrid;
    }

    void OnSliderValueChanged(object sender, ValueChangedEventArgs e)
    {
        boxView.Color = new Color(redSlider.Value, greenSlider.Value, blueSlider.Value);
    }
}