Grid

Browse sample. 浏览示例

.NET MAUI Grid.

.NET Multi-platform App UI (.NET MAUI) Grid 是一种布局,它将其子级组织为可以有比例大小或绝对大小的行和列。 默认情况下,Grid 包含一行和一列。 此外,还可以将 Grid 用作包含其他子布局的父布局。

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

Grid 类定义以下属性:

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

所有这些属性都由 BindableProperty 对象提供支持,这意味着这些属性可以作为数据绑定的目标并设置样式。

行和列

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

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             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

Default .NET MAUI Grid layout.

可以使用 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://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="GridDemos.Views.XAML.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 对象都跟 1* 一样将 Width 设置为 *,这意味着屏幕的宽度在两列下方相等。

重要

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

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

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

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="GridDemos.Views.XAML.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 跨两列:

Basic .NET MAUI Grid layout.

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

等效 C# 代码如下:

public class BasicGridPage : ContentPage
{
    public BasicGridPage()
    {
        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 need to be added to the
        // Grid to obtain the default row and column settings.
        grid.Add(new BoxView
        {
            Color = Colors.Green
        });
        grid.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.Add(new BoxView
        {
            Color = Colors.Blue
        }, 1, 0);
        grid.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.Add(new BoxView
        {
            Color = Colors.Teal
        }, 0, 1);
        grid.Add(new Label
        {
            Text = "Row 1, Column 0",
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.Center
        }, 0, 1);

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

        // Row 2
        // Alternatively, the BoxView and Label can be positioned in cells with the Grid.SetRow
        // and Grid.SetColumn methods. Here, the Grid.SetColumnSpan method is used to span two columns.
        BoxView boxView = new BoxView { Color = Colors.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.Add(boxView);
        grid.Add(label);

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

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

注意

Grid 还可定义 AddWithSpan 扩展方法,该方法将视图添加到具有指定行和列跨度的指定行和列处的 Grid

简化行和列定义

在 XAML 中,可以使用简化的语法指定 Grid 的行和列特征,这样就不必为每一行和每一列定义 RowDefinitionColumnDefinition 对象。 实际上,可以将 RowDefinitionsColumnDefinitions 属性设置为包含以逗号分隔的 GridUnitType 值的字符串,以便内置于 .NET MAUI 中的类型转换器从其创建 RowDefinitionColumnDefinition 对象:

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

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

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

行和列之间的间距

默认情况下,Grid 行和列之间没有空格。 这可以通过分别设置 RowSpacingColumnSpacing 属性来更改:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="GridDemos.Views.XAML.GridSpacingPage"
             Title="Grid spacing demo">
    <Grid RowSpacing="6"
          ColumnSpacing="6">
        ...
    </Grid>
</ContentPage>

此示例创建了 Grid,其行和列由大小为 6 个设备无关单位的空间分隔:

.NET MAUI Grid with spacing between cells.

提示

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

等效 C# 代码如下:

public class GridSpacingPage : ContentPage
{
    public GridSpacingPage()
    {
        Grid grid = new Grid
        {
            RowSpacing = 6,
            ColumnSpacing = 6,
            ...
        };
        ...

        Content = grid;
    }
}

保持同步

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

  • Start
  • Center
  • End
  • Fill

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

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="GridDemos.Views.XAML.GridAlignmentPage"
             Title="Grid alignment demo">
    <Grid>
        <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 对象在水平方向上的对齐方式完全相同,但使用不同的垂直对齐方式:

Cell alignment in a .NET MAUI Grid.

等效 C# 代码如下:

public class GridAlignmentPage : ContentPage
{
    public GridAlignmentPage()
    {
        Grid grid = new Grid
        {
            RowDefinitions =
            {
                new RowDefinition(),
                new RowDefinition(),
                new RowDefinition()
            },
            ColumnDefinitions =
            {
                new ColumnDefinition(),
                new ColumnDefinition(),
                new ColumnDefinition()
            }
        };

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

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

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

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

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

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

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

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

        grid.Add(new BoxView
        {
            Color = Colors.BlueViolet
        }, 2, 2);
        grid.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://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:converters="clr-namespace:GridDemos.Converters"
             x:Class="GridDemos.Views.XAML.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 Height="500" />
            <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 x:DataType="Slider"
                   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 x:DataType="Slider"
                   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 x:DataType="Slider"
                   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 包含用于处理 BoxView 所显示颜色的 Slider 对象,以及显示每个 Slider 值的 Label 对象:

Nested .NET MAUI Grid objects.

重要

嵌套 Grid 对象和其他布局的深度越深,执行的布局计算就越多,这可能会影响性能。 有关详细信息,请参阅选择正确的布局

等效 C# 代码如下:

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

    public ColorSlidersGridPage()
    {
        // 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 { HeightRequest = 500 },
                new RowDefinition()
            }
        };

        boxView = new BoxView { Color = Colors.Black };
        rootGrid.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.Add(redSlider);

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

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

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

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

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

        // Place the child Grid in the root Grid
        rootGrid.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);
    }
}