dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.05k stars 1.73k forks source link

Using CollectionView IsGrouped="True" bound to ObservableCollection causes crash #18481

Open megukaphii opened 11 months ago

megukaphii commented 11 months ago

Description

When using a CollectionView where the ItemSource is set to a binding of type ObservableCollection, and IsGrouped is set to True, the app crashes if the ObservableCollection is updated such that: there are more than 2 items in the first group, or there is more than 1 item in any subsequent group.

I tested this by copy+pasting from Microsoft's official CollectionView grouping docs in a brand new project: https://learn.microsoft.com/en-us/dotnet/maui/user-interface/controls/collectionview/grouping

Steps to Reproduce

  1. Download the linked repo
  2. Run the project on Windows and click the "Load Animals" button
  3. Note that the program does not crash if you modify to have only 1 animal in the second "Monkeys" group, and that it does crash if you subsequently add a third animal to the "Bears" group

Expected Outcome: The groups appear correctly. Actual Outcome: The app crashes without an exception thrown.

Link to public reproduction project repository

https://github.com/megukaphii/GroupedCollectionViewBug

Version with bug

8.0.0-rc.2.9373

Is this a regression from previous behavior?

Not sure, did not test other versions

Last version that worked well

Unknown/Other

Affected platforms

Windows, I was not able test on other platforms

Affected platform versions

Windows SDK 10.0.17763.0

Did you find any workaround?

No response

Relevant log output

No response

drasticactions commented 11 months ago

Trying out your repro, if you have grouped items already in the list when it is created, those should render. Adding new items causes a native exception.

Vroomer commented 11 months ago

I experienced the same issue in earlier previews of .Net 8. Looks like a regression.

sjorsmiltenburg commented 11 months ago

I work with a collectionview bound to a large list of grouped items that I need to update often. Using an observablecollection without AddRange support causes way to many updates / events for me. That's why I'm using a List that I can pre-populate and instantly swap out.

XamlTest commented 11 months ago

Verified this on Visual Studio Enterprise 17.8.0 Preview 5.0(8.0.0-rc.2.9373). Repro on Windows 11, not repro on Android 14.0-API34 with below Project: GroupedCollectionViewBug.zip

ghost commented 11 months ago

We've added this issue to our backlog, and we will work to address it as time and resources allow. If you have any additional information or questions about this issue, please leave a comment. For additional info about issue management, please read our Triage Process.

retepz commented 10 months ago

Can confirm this is a .NET 8 regression as I didn't have this problem in my app on .NET 7.

mdbill commented 10 months ago

Backlog? Seems critical...or maybe that's just me. What's the workaround for my app with a grouped observablecollection? I'm still stuck forcing my app to run on Maui 7.0.52 !! Yes, that old, because the layout hasn't worked after that version. I thought .net8 might finally save me, so I tried the 'upgrade'. This is why I've abandoned MAUI for Flutter on all new projects in 2023. Flutter is such a joy.

Agistaris commented 8 months ago

I have been able to use 'IsGrouped' with Observable Collection, however when scrolling group items it causes a memory leak on iOS... It's unusable in the current state. Using the interpreter works, but I think MAUI should account for this on iOS. Something is lost in translation when AOT compiler runs on release builds.

AndreKraemer commented 3 months ago

I can confirm, that the native crash still happens in .NET MAUI 8.0.60 and that it didn't happen in Version 7.X

When you attach a native debugger to the process, you get the following exception message:

Unhandled Exception at 0x00007FFE244052F5 (Microsoft.ui.xaml.dll) in CollectionViewSamples.exe: 0xC000027B: Application internal Exception (Parameter: 0x000001FAA1110130, 0x0000000000000003)

To everyone looking for a workaround until this issue is resolved: Instead of dynamically adding and removing items in the Collection, simply replace the entire collection.

Here’s what I had initially:

public class GroupSampleViewModel : BaseViewModel<Person>
{

  public ObservableCollection<PersonsByCompany> Items {get ; } = [];

  public GroupSampleViewModel(IDataStore<Person> dataStore) : base(dataStore)
  {
  }

  public override async Task Initialize()
  {
    IsBusy = true;

    try
    {
      var persons = await DataStore.GetItemsAsync(true);
      var group = persons.GroupBy(p => p.CompanyName)
                        .Select(group => new PersonsByCompany(group.Key, [.. group]))
                        .ToList();

      // this will crash on windows!
      // see: https://github.com/dotnet/maui/issues/18481
      foreach (var item in group)
      {
        Items.Add(item);
      }
     }
    finally
    {
      IsBusy = false;
    }
    await base.Initialize();
  }
}

And I changed it to this:

public class GroupSampleViewModel : BaseViewModel<Person>
{

  // changed Items to a full property, so we can raise PropertyChanged in the 
  // base class
  private ObservableCollection<PersonsByCompany> _items = [];
  public ObservableCollection<PersonsByCompany> Items
  {
    set => SetProperty(ref _items, value);
    get => _items;
  }
  public GroupSampleViewModel(IDataStore<Person> dataStore) : base(dataStore)
  {
  }

  public override async Task Initialize()
  {
    IsBusy = true;

    try
    {
      var persons = await DataStore.GetItemsAsync(true);
      var group = persons.GroupBy(p => p.CompanyName)
                        .Select(group => new PersonsByCompany(group.Key, [.. group]))
                        .ToList();

      // dynamically adding and removing items from the Items-Collection causes a crash on Windows
      // because of that, I replace the whole collection
      // see: https://github.com/dotnet/maui/issues/18481
      //foreach (var item in group)
      //{
      //  Items.Add(item);
      //}

      Items = new ObservableCollection<PersonsByCompany>(group);
    }
    finally
    {
      IsBusy = false;
    }
    await base.Initialize();
  }
}
SandipAhluwalia commented 4 weeks ago

@AndreKraemer Your workaround suggestion of replacing the whole collection works for me. Thank you

nephesh commented 1 week ago

I had the same issue but found a different workaround.

I've found that setting the CollectionView IsVisible to False before adding items to the ObservableCollection, and then setting IsVisible back to True prevents the control from crashing. I only do this if the platform is WinUI. On Android, it's working fine.

I'm not proud of this workaround, but it prevents me from changing all the code that dynamically adds grouped items to my ObservableCollection<Grouping<string, MyClass>>.

Putting this in code, I'm doing something like:

  if (DeviceInfo.Platform == DevicePlatform.WinUI)
  {      
      myCollectionView.IsVisible = false; //BUG_CollectionView_IsGrouped_True_Windows
      await _viewModel.LoadData();
      myCollectionView.IsVisible = true;  //BUG_CollectionView_IsGrouped_True_Windows
  }

I'm using SDK 7.0.311 forced in the global.json to ensure it uses the correct SDK. I have installed the workloads: maui, maui-desktop and maui-windows.

Hopefully, when this bug is corrected, I'll return to the previous code.

crwsolutions commented 1 week ago

I had the same issue but found a different workaround.

Tnx! It also works in my solution with MVVM, snippet from my code:

#if WINDOWS
            CollectionIsVisible = false;
#endif

            Categories.Fuse(incomingList);

#if WINDOWS
            CollectionIsVisible = true;
#endif