How to get DispatcherQueue in WinUI 3 Desktop using Windows App SDK
Asked Answered
E

3

15

In WPF all controls inherit DispatcherObject & its easy to get to the Dispatcher.

How would I get the DispatcherQueue using WinUI 3 Windows App SDK and use it in a ViewModel?

EDIT

My implementation which expands on mm8's most appreciated answer.

Create a Property in my ViewModel

public Microsoft.UI.Dispatching.DispatcherQueue TheDispatcher { get; set; }

Then grab the dispatcher in my MainPage.xaml.cs codebehind Constructor

ViewModel.TheDispatcher = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread();

Now I have the dispatcher n my VM so its easy to use from the VM:

TheDispatcher.TryEnqueue(() =>
{
     // some ui thread work
});

Note: I didnt post this as an answer as there is one, this is my implementation to help anyone interested.

Eddins answered 8/11, 2021 at 14:42 Comment(0)
H
29

Call the DispatcherQueue.GetForCurrentThread() API on the dispatcher thread.

If you create your view models on the dispatcher thread, you could call the method in the constructor or directly in the initializer as I demonstrated in your other question.

If you create your view models on a background thread, you will have to inject them with a DispatcherQueue that you create before on an actual dispatcher thread, e.g.:

DispatcherQueue dispatcherQueue = DispatcherQueue.GetForCurrentThread();

Task.Run(() => 
{
    ViewModel vm = new ViewModel(dispatcherQueue);
    ...
});
Hypno answered 10/11, 2021 at 16:6 Comment(3)
I cannot upvote this answer enough. I am shocked at how difficult it is to find this guidance elsewhere, say, in MS docs, which don't even have the namespace updated properly. Thank you. Anyone else coming here READ THIS ANSWER CAREFULLY. You must call GetForCurrentThread() on the UI thread and then reference it for later use from other threads!Subtorrid
in what case i would use DispatcherQueue.TryEnqueue(() => { Your code }); and Task.Run(()=>{ your code }); lets say i have a loop of 1000 view models and i call . public async Task DoWork() on each vm, i can do it either loop through them and just do vm.DoWork(); (without await) or dispatcherQueue.TryEnqueue(async () => { await vm.DoWork(); }); which way is prefered and why ? lest say DoWork() does some long job and then updates a property that calls OnPropertyChanged();Sabra
@Sabra - please create another question to ask this.Evanesce
L
4

Yes, getting DispatcherQueue is different from WPF, it is something like that in WinUI3:

var dispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread();

After that you can use TryEnqueue method.

Lifton answered 10/11, 2021 at 10:2 Comment(0)
B
4

I can understand your pain while using WINUI-3 If you are in threadworkerPool and if you want to go back to the main thread Dispatcher will not be supported by WINUI-3 as of now. Instead of that use

Microsoft.UI.Dispatching.DispatcherQueue.TryEnqueue(() => {
         Your code 
    });   

I have wasted a lot of time on this, In the last I got this, hope this will work for you as well.

Barri answered 1/12, 2021 at 4:59 Comment(1)
Not sure why people upvoted this. The code won't compile. What's needed is an instance of class DispatcherQueue. Specifically, the instance corresponding to a current UI object. The whole point of the question and the accepted answer is understanding how to get hold of an appropriate instance! [AFAIK, there is no static instance, because a Windows Desktop app might have multiple windows. An attempt to touch UI of one window from another window's queue is not valid.]Evanesce

© 2022 - 2024 — McMap. All rights reserved.