CollectionView layout issues with nested CollectionView (unpackaged on Windows)

TerryH 55 Reputation points
2023-03-19T16:20:14.0733333+00:00

I'm working with an unpacked app targeting Windows 10. (<WindowsPackageType>None</WindowsPackageType>)

I've had this problem with CollectionView since the release of MAUI where items are not sized properly on first display. The user must resize the main parent window horizontally to fix the issue. This not acceptable because when using the app it's too disruptive to have to continually resize the app to correct the layout in order to see the contents of the view properly. CollectionView is one of the main views for displaying collections, and I've tried ListView but it has the same issues. I prefer CollectionView because I make use of the empty collection template view and I've been hoping with each new update that it would fix this issue. I'm on VS 17.5.2.

To show this behavior, I based a sample app off of MauiApp2 that is included in the samples download from GitHub for MAUI, and modified the DetailPage to hold the collection view.

The DetailPage has a nested CollectionView using a DataTemplateSelector.

My DetailPage:


<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApp2.DetailPage"
             xmlns:viewmodel="clr-namespace:MauiApp2.ViewModel" 
             xmlns:view="using:MauiApp2.View"
             x:DataType="viewmodel:DetailViewModel"
             Title="DetailPage">

    <ContentPage.Resources>
        <ResourceDictionary>
            <DataTemplate x:Key="thingObjectViewTemplate"
                          x:DataType="{x:Type viewmodel:ThingObject}">
                <view:ThingObjectView />
            </DataTemplate>
        </ResourceDictionary>
    </ContentPage.Resources>    

    <CollectionView 
        ItemsSource="{Binding TopCollection}" 
        ItemSizingStrategy="MeasureAllItems"
        ItemTemplate="{StaticResource thingObjectViewTemplate}">

    </CollectionView>

</ContentPage>

I have an ObservableCollection of a base class that is filled with two types of subclasses:


public partial class BaseObject : ObservableObject
{
    [ObservableProperty]
    private string nestedString1;
    [ObservableProperty]
    private string nestedString2;
}
public partial class ThingObject : ObservableObject
{
    public ThingObject()
    {
        nestedObjects = new ObservableCollection<BaseObject>();
    }

    [ObservableProperty]
    private string thingText;

    [ObservableProperty]
    private string thingText2;

    [ObservableProperty]
    private string thingText3;

    [ObservableProperty]
    private string thingText4;

    [ObservableProperty]
    private ObservableCollection<BaseObject> nestedObjects;
}
public partial class SubObject1 : BaseObject
{
    [ObservableProperty]
    private string obj1String3;
    [ObservableProperty]
    private string obj1String4;
}
public partial class SubObject2 : BaseObject
{
    [ObservableProperty]
    private string obj2String3;

    [ObservableProperty]
    private string obj2String4;
}
public class ThingTemplateSelector : DataTemplateSelector
{
    public DataTemplate Thing1Template { get; set; }
    public DataTemplate Thing2Template { get; set; }

    protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
    {
        switch (item)
        {   
            case SubObject1:
                return Thing1Template;
            case SubObject2:
                return Thing2Template;

            default:
                throw new Exception($"item is not of the correct type for use in the view: {item.GetType()}");
        }
    }
}

Here are the data templates for each of the views:


<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:view="using:MauiApp2.View"
             xmlns:viewmodel="using:MauiApp2.ViewModel"
             xmlns:mauiApp2="using:MauiApp2"
             x:Class="MauiApp2.View.ThingObjectView">

    <ContentView.Resources>
        <ResourceDictionary>
            <DataTemplate x:Key="obj1Template"
                          x:DataType="{x:Type viewmodel:SubObject1}">
                <view:Obj1View/>
            </DataTemplate>
            <DataTemplate x:Key="obj2Template"
                          x:DataType="{x:Type viewmodel:SubObject2}">
                <view:Obj2View/>
            </DataTemplate>
            <mauiApp2:ThingTemplateSelector x:Key="thingTemplateSelector"
                                                    Thing1Template="{StaticResource obj1Template }"
                                                    Thing2Template="{StaticResource obj2Template}" />

        </ResourceDictionary>
    </ContentView.Resources>
    <Frame BorderColor="AntiqueWhite">
        <Grid RowDefinitions="Auto, Auto, Auto, Auto, *" Padding="3,3" RowSpacing="3" ColumnSpacing="3">

            <Label Grid.Row="0" Text="{Binding ThingText}" />
            <Label Grid.Row="1" Text="{Binding ThingText2}" />
            <Label Grid.Row="2" Text="{Binding ThingText2}" />
            <Label Grid.Row="3" Text="{Binding ThingText2}" />

            <CollectionView Grid.Row="4" ItemsSource="{Binding NestedObjects}"
                            ItemTemplate="{StaticResource thingTemplateSelector}"
                            ItemSizingStrategy="MeasureAllItems">

            </CollectionView>

        </Grid>
    </Frame>
</ContentView>

<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApp2.View.Obj1View">
    
    <Frame BorderColor="Blue">
        <VerticalStackLayout Spacing="3">
            <Label Text="{Binding NestedString1}" />
            <Label Text="{Binding NestedString2}" />
            <Label Text="{Binding Obj1String3}" />
            <Label Text="{Binding Obj1String4}" />
        </VerticalStackLayout>
    </Frame>
</ContentView>


<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApp2.View.Obj2View">

    <Frame BorderColor="Orange">
        <VerticalStackLayout Spacing="3">
            <Label Text="{Binding NestedString1}" />
            <Label Text="{Binding NestedString2}" />
            <Label Text="{Binding Obj2String3}" />
            <Label Text="{Binding Obj2String4}" />
        </VerticalStackLayout>
    </Frame>
</ContentView>

The issue will mostly resolve by resizing the main window horizontally (vertically has no effect), but it still leaves parts of the display difficult to access.

VS.2022.17.4.4_SquashedCollectionView

Interesting thing is when looking at the Live Tree view, it seems like it knows where the control should be displayed, but is not.
VS.2022.17.4.4_SquashedCollectionView_LiveTree

I've found several layout issues with CollectionView in Google searches that are known but do not have viable workarounds.

I have a project release coming up soon and this is a show-stopper. I would appreciate any feedback on work arounds, even if a temporary "hack", to make it display properly. Obviously, I would prefer it to be officially fixed, but at this point, I'm willing to put in a work around.

Thanks!

.NET MAUI
.NET MAUI
A Microsoft open-source framework for building native device applications spanning mobile, tablet, and desktop.
2,869 questions
{count} votes

1 answer

Sort by: Most helpful
  1. TerryH 55 Reputation points
    2023-05-01T01:41:32.84+00:00

    Here's a working version using VerticalStackLayout BindableLayout. Basically, just never nest CollectionView.

    
    <ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:view="using:MauiApp2.View"
                 xmlns:viewmodel="using:MauiApp2.ViewModel"
                 xmlns:mauiApp2="using:MauiApp2"
                 x:Class="MauiApp2.View.ThingObjectView">
    
        <ContentView.Resources>
            <ResourceDictionary>
                <DataTemplate x:Key="obj1Template"
                              x:DataType="{x:Type viewmodel:SubObject1}">
                    <view:Obj1View/>
                </DataTemplate>V
                <DataTemplate x:Key="obj2Template"
                              x:DataType="{x:Type viewmodel:SubObject2}">
                    <view:Obj2View/>
                </DataTemplate>
                <mauiApp2:ThingTemplateSelector x:Key="thingTemplateSelector"
                                                        Thing1Template="{StaticResource obj1Template }"
                                                        Thing2Template="{StaticResource obj2Template}" />
    
            </ResourceDictionary>
        </ContentView.Resources>
        <Frame BorderColor="AntiqueWhite" Margin="5">
            <Grid RowDefinitions="Auto, Auto, Auto, Auto, *" Padding="3,3" RowSpacing="3" ColumnSpacing="3">
    
                <Label Grid.Row="0" Text="{Binding ThingText}" />
                <Label Grid.Row="1" Text="{Binding ThingText2}" />
                <Label Grid.Row="2" Text="{Binding ThingText2}" />
                <Label Grid.Row="3" Text="{Binding ThingText2}" />
    
    			<!--Replace CollectionView with this-->
                <VerticalStackLayout BindableLayout.ItemsSource="{Binding NestedObjects}" 
                                        Grid.Row="4" 
                                        BindableLayout.ItemTemplateSelector="{StaticResource thingTemplateSelector}" />
            </Grid>
        </Frame>
    </ContentView>
    

    Here's the result - all nested items are sized properly and the outer CollectionView provides scrolling capability.

    WorkingBindableLayout

    1 person found this answer helpful.