Search code examples
c#multithreadingmvvmwinui-3uno-platform

WinUi MVVM, handle events from model on UI thread


To start with I'm from a WPF world where I'm used to using MVVM, however my knowledge isn't up to date with regards to the new .net API and WinUI.

I'm currently trying to create a new POC using UNO Platform (which is more or less WinUI api) and MVVM, however I'm currently stuck. The problem is that I'm firing an event in my model that the view model subscribes to. The event is running on a background thread so the UI will not get updated when the view model updates the properties from the event, due to the background thread. WPF's approach to get the UI thread isn't available.

The suggestion I found is to use DispatcherQueue.GetForCurrentThread(); in the constructor of the view model. However, I'm using microsofts IOC Microsoft.Extensions.Hosting to register the view model, so the constructor is called on a background thread and therefor having the DispatcherQueue.GetForCurrentThread(); to get the UI thread doesn't work. Another solution would be to store the dispatcherQueue in the App.cs, but that just doesn't seems like a great idea to access the dispatcherQueue through App.

So in short, how do I update the view models properties on the UI thread when receiving an event from the model ?


Solution

  • Another solution would be to store the dispatcherQueue in the App.cs, but that just doesn't seems like a great idea to access the dispatcherQueue through App

    Why not? That's what you do in WPF when you use the Application.Current.Dispatcher API.

    You could add this property to your App class:

    public DispatcherQueue DispatcherQueue { get; } = DispatcherQueue.GetForCurrentThread();
    

    ...and then use the DispatcherQueue as usual:

    Task.Run(async () =>
    {
        var dispatcherQueue = (App.Current as App).DispatcherQueue;
        dispatcherQueue.TryEnqueue(() => {
            //set property...
        });
    });
    

    If you don't want to access the DispatcherQueue using the App class, you could of course inject it into your container like you would do with any other object. Just make sure that you initialize the DispatcherQueue on the UI thread.