UI freezing despite ObservableCollection<T> being updated

64 Views Asked by At

could you please help me to understand how to resolve issue of the UI being slow responsive while updating ObservableCollection. The problem is that I'm processing 50K lines file and all works very well untill I start adding these items to the ViewModel's source observable collection.

Even with the fastest possible way it still works very slow

var enumerator = service.SeedCSVFileDataAsync(csvFilePath);

   
    await foreach (var item in enumerator.WithCancellation(CancellationToken.None))
    {
        userObjects.Add(item);
        Source.Add(item); // Here is where the slow begin

    }

I understand that adding 50k items to the observable collection generates tons of events which is the root cause of slow response issue however when I'm tryinng to cheat this issue by re-initialize observablecollection with pre-populated collection it stops recieve any events at all.

Source = new ObservableCollection<ADUserObject>(userObjects); after this no data on the screen even if you try to add anything

I think this is because of issues in the generated code and architecture but I can't figure out this by my self, so maybe someone already resolved this issue.

I would be very appreciate you'll if you could help me to understand how to resolve this issue. Again the 50k lines file reads and populates IEnumerable collection with in the few milliseconds with out blocking the ui, the problem appears only when I'm start working with the ObservableCollection.

Appreciate your response in advance, Best regards, Maks.

EDit BTW I just realized that most likely the reason of why this trick isn't work

Source = new ObservableCollection<ADUserObject>(userObjects);

is beacuse compiler do it's own magick with *.g.cs files based on on the framework settings ... did anyone faced already this problem ?

2

There are 2 best solutions below

2
Vinxian On

Are you calling PropertyChanged(this, new PropertyChangedEventArgs("Source")); from INotifyPropertyChanged after setting the Source variable?

An observable collection notifies the UI when its contents are altered, but if the reference to the observable collecition itself is changed no notification is send by default.

Consider adding the following code to never forget notifying the UI.

private ObservableCollection<T> _source;
public ObservableCollection<T> Source
{
    get => _source;
    set
    {
        if (value != _source)
        {
            _source = value;
            PropertyChanged(this, new PropertyChangedEventArgs("Source"));
        }
    }
}
0
Max Zaikin On

Alright, problem solved. Thank's to Christian Nagel for good thouds given in his articleWhat’s the SynchronizationContext used for? and Filip Ekberg for great course at Pluralsight "Asynchronous Programming in C#10"

Here is the raw snippet which is smoothly loading 50k lines in the data grid without frozing the UI thread (pls don't judge me too hard, I know it need some refactoring...)

/// <summary>
/// [MZ]
/// </summary>
/// <param name="parameter"></param>
public async Task<IEnumerable<T>> ProcessCSVData(string csvFilePath, CSVDataService service)
{
    
    Microsoft.UI.Dispatching.DispatcherQueue dispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread();

    List<T> _mObjects = new List<T>();

    Source.Clear();        

    await  Task.Run(async () => {

        var enumerator = service.SeedCSVFileDataAsync(csvFilePath);

        await foreach (var item in enumerator.WithCancellation(CancellationToken.None))
        {
            _mObjects.Add(item);
            //Source.Add(item);

            await dispatcherQueue.EnqueueAsync(() =>
            {
                Source.Add(item);
            });
        }

    });
    return _mObjects;
}

Appreciate your answers and participation in this problem, Best regards, Maks.

P.S. I also have open an issue on the GitHub, just to make sure that this isn't a bug for thous who are interested, here is the link: UI Thread slow response due to the populating of 50k records file in ViewModel.Source observable collection #4688