0
votes

I need to continuously adjust the width and height of items within a CollectionView according to the page dimensions.

Here's an example of what I'm currently doing:

MainPage.xaml:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:self="clr-namespace:DynDimCollView"
             x:Name="Root"
             mc:Ignorable="d"
             x:Class="DynDimCollView.MainPage">
    <StackLayout>
        <CollectionView x:Name="collectionView" HeightRequest="{Binding ItemsHeight, Source={x:Reference Root}}"
                        ItemsSource="{Binding Items, Source={x:Reference Root}}"
                        BackgroundColor="LightGray">
            <CollectionView.ItemsLayout>
                <LinearItemsLayout Orientation="Horizontal"/>
            </CollectionView.ItemsLayout>
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <self:CustomFrame WidthRequest="{Binding ItemsWidth, Source={x:Reference Root}}"
                                      BorderColor="Blue">
                        <StackLayout>
                            <Label Text="{Binding Name}"/>
                        </StackLayout>
                    </self:CustomFrame>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </StackLayout>
</ContentPage>

MainPage.xaml.cs:

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
        Items = new ObservableCollection<Item> { new Item { Name = "Item1" }, new Item { Name = "Item2" }, new Item { Name = "Item3" }, new Item { Name = "Item4" }, new Item { Name = "Item5" } };
    }

    protected override void OnSizeAllocated(double width, double height)
    {
        base.OnSizeAllocated(width, height);
        ItemsHeight = height / 4;
        ItemsWidth = width / 4;
    }

    public static BindableProperty ItemsProperty =
        BindableProperty.Create(
            nameof(Items),
            typeof(ObservableCollection<Item>),
            typeof(MainPage),
            null,
            BindingMode.OneWay);


    public static BindableProperty ItemsHeightProperty =
        BindableProperty.Create(
            nameof(ItemsHeight),
            typeof(double),
            typeof(MainPage),
            null,
            BindingMode.OneWay);

    public static BindableProperty ItemsWidthProperty =
        BindableProperty.Create(
            nameof(ItemsWidth),
            typeof(double),
            typeof(MainPage),
            null,
            BindingMode.OneWay);

    public ObservableCollection<Item> Items
    {
        get => (ObservableCollection<Item>)GetValue(ItemsProperty);
        set => SetValue(ItemsProperty, value);
    }

    public double ItemsHeight
    {
        get => (double)GetValue(ItemsHeightProperty);
        set => SetValue(ItemsHeightProperty, value);
    }

    public double ItemsWidth
    {
        get => (double)GetValue(ItemsWidthProperty);
        set => SetValue(ItemsWidthProperty, value);
    }
}

Notice the override of OnSizeAllocated where the item size is set.

It seems to be working fine but strangely on UWP it works only when you change the height of the window. If you just change the window's width the items do not resize.

I tried to call ForceLayout on WidthRequest property changes (within the CustomFrame) but it does nothing.

Am I doing something wrong or is this a bug?

1

1 Answers

0
votes

The OnSizeAllocated method is called whenever a Page is allocated a new size, which happens whenever the device is rotated.

In your case , you should also override the method SizeChanged of ContentPage .

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:self="clr-namespace:DynDimCollView"
             x:Name="Root"
             mc:Ignorable="d"
             SizeChanged="ContentPage_SizeChanged"
             x:Class="DynDimCollView.MainPage">

And handle the layout when you change the size of window .

private void ContentPage_SizeChanged(object sender, EventArgs e)
        {
            var width = this.Width;
            var height = this.Height;

            if(width!=0&&height!=0)
            {
                 // ...
            }
        }