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.
Interesting thing is when looking at the Live Tree view, it seems like it knows where the control should be displayed, but is not.
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!