How to Asynchronously Update an ObservableCollection in C# WPF

Implement an ObservableCollection that supports asynchronous updates in WPF, with examples of AsyncObservableCollection and PageMstCollection.

TechPublished 1 min read

In a WPF application, you often need to synchronize data between the UI thread and a background thread.
For that, we'll implement an ObservableCollection that fetches data asynchronously and reflects it in the UI.
This article explains how to do that.

Asynchronous Updates to ObservableCollection

In WPF, changes to the UI must be made on the UI thread. However, when you need to update the UI while performing asynchronous work, BindingOperations.EnableCollectionSynchronization combined with a lock statement makes this easy to achieve.

public class PageMstCollection : ObservableCollection<PageMstViewModelEntity>
{
    private readonly object _lock = new object();
    private readonly IPageMstRepository _pageMstRepository;

    public PageMstCollection(IPageMstRepository pageMstRepository)
    {
        _pageMstRepository = pageMstRepository;
        BindingOperations.EnableCollectionSynchronization(this, _lock);
    }

    public async Task LoadDataAsync()
    {
        var newData = await Task.Run(() =>
        {
            return _pageMstRepository.GetData().Select(entity => new PageMstViewModelEntity(entity));
        });

        lock (_lock)
        {
            Clear();
            foreach (var item in newData)
            {
                Add(item);
            }
        }
    }
}

In this class, the LoadDataAsync method asynchronously fetches data from _pageMstRepository, and uses a lock statement to safely update the ObservableCollection for the UI thread.

ViewModel Usage Example

Finally, here's an example of using these classes from a ViewModel.

public class MainViewModel : ViewModelBase
{
    private readonly PageMstCollection _pageMstCollection;

    public MainViewModel(IPageMstRepository pageMstRepository)
    {
        _pageMstCollection = new PageMstCollection(pageMstRepository);
        LoadData();
    }

    private async void LoadData()
    {
        await _pageMstCollection.LoadDataAsync();
        OnPropertyChanged(nameof(PageMstCollection));
    }

    public ObservableCollection<PageMstViewModelEntity> PageMstCollection => _pageMstCollection;
}

By calling the LoadDataAsync method from the ViewModel, you can load data asynchronously in the background and reflect it in the UI. The OnPropertyChanged method is used to notify that the PageMstCollection property has changed.

Now you know how to build an ObservableCollection that updates asynchronously and use it in a WPF application.