How to use a Grid with Bindable Layout (more than one column)

Chr*_*ett 5 grid layout bindable xamarin xamarin.forms

In Xamarin.Forms 3.5 Microsoft introduced us to bindable layouts which can be used to dynamically fill layouts (e.g. StackLayout, Grid, etc.).

To use this in a grid with a single column is pretty straightforward:

<Grid BindableLayout.ItemsSource="{Binding Items}">
    <BindableLayout.ItemTemplate>
        <DataTemplate>
            <Label Text="{Binding MyProperty}"/>
        </DataTemplate>
    </BindableLayout.ItemTemplate>
</Grid>
Run Code Online (Sandbox Code Playgroud)

Now my question is how this can be used to populate a grid with more than one column due to the fact that DataTemplate only allows one view as content. Sure I could but another Grid in it but this would totally nullify the value of bindable layout in a Grid.

Ole*_*nyi 1

我创建了一个提供视图索引作为可绑定属性的行为。就我而言,我始终拥有相同数量的项目,因此我可以设置 ColumnDefinitions/RowDefinitions 并将 Grid.Column/Row 绑定到行为的 Index 属性。

    public sealed class IndexProviderBehavior : Behavior<View>
    {
        View _view;

        public static readonly BindableProperty IndexProperty =
        BindableProperty.Create(nameof(Index), typeof(int), typeof(IndexProviderBehavior),
            defaultBindingMode: BindingMode.OneWayToSource);

        public int Index
        {
            get => (int)GetValue(IndexProperty);
            set => SetValue(IndexProperty, value);
        }

        protected override void OnAttachedTo(View bindable)
        {
            base.OnAttachedTo(bindable);
            _view = bindable;
            bindable.ParentChanged += OnParentChanged;
            SetupIndex();
        }

        protected override void OnDetachingFrom(View bindable)
        {
            base.OnDetachingFrom(bindable);
            _view.ParentChanged -= OnParentChanged;
            _view = null;
        }

        private void OnParentChanged(object sender, EventArgs e)
        {
            SetupIndex();
        }

        private void SetupIndex()
        {
            if (_view.Parent is Layout layout)
            {
                Index = layout.Children.IndexOf(_view);
                return;
            }

            Index = 0;
        }
    }
Run Code Online (Sandbox Code Playgroud)

用法:

            <Grid
                ColumnDefinitions="*,*,*,*,*,*,*"
                BindableLayout.ItemsSource="{Binding Items}">
                <BindableLayout.ItemTemplate>
                    <DataTemplate>
                        <Label
                            Text="{Binding .}"
                            Grid.Column="{Binding Index, Source={x:Reference indexBehavior}}"
                            >
                            <Label.Behaviors>
                                <behaviors:IndexProviderBehavior x:Name="indexBehavior" />
                            </Label.Behaviors>
                        </Label>
                    </DataTemplate>
                </BindableLayout.ItemTemplate>
            </Grid>
Run Code Online (Sandbox Code Playgroud)