10

A WinUI 3 question about accessing the UI thread from another thread, say, a Timer tick.

In WinForms that was extremely easy with a (someControl).InvokeRequired and .Invoke. In WPF we had to add .Dispatcher. and in UWP we had to specify a specific dispatcher: Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(...). But it still all worked just fine.

When I port my UWP solution (an extremely simple program to just show the issue), and adjust the name of the class (and thus its constructor), it still builds fine, but when I run it, I get an "a method was called at an unexpected time" exception. (Again: works fine as a UWP app)

I'll include my test code below:

Any idea what's happening here? HOW do I fix this, and, bonus answer: why does this happen in WinUI 3 and not in UWP?

(And yes, I'm aware of DispatcherTimer, I use Timer to demonstrate my problem: in my actual app I use something far more complicated than a timer, and I wanted to keep the demo code as concise and short as possible).

Demo code:

    using Microsoft.UI.Xaml;
    using System;
    using System.Threading;
    using Windows.UI.Core;
    
    namespace WinUI3NotOwner
    {
        public sealed partial class MainWindow : Window
        {
            public Timer timer;
            public int counter = 0;
    
            public MainWindow()
            {
                this.InitializeComponent();
                timer = new Timer(TimerTick, null, 1000, 1000);
            }
    
            public void TimerTick(Object stateInfo)
            {
                if (++counter == 3)
                {
                    Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                    () => { TbTest.Text = "Works!"; }); // WinUI 3 code. Ignore the warning: we actually DON'T want to wait for its completion!
                }
            }
        }
    }

XAML code used:

    <Window
        x:Class="WinUI3NotOwner.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:WinUI3NotOwner"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Grid>
            <TextBox x:Name="TbTest" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="50,50,0,0" TextWrapping="Wrap" Text="TextBox" Width="200" Height="40"/>
        </Grid>
    
    </Window>

1 Answer 1

12

You should use the Microsoft.UI.Dispatching.DispatcherQueue.

public void TimerTick(Object stateInfo)
{
    if (++counter == 3)
    {
        //Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
        //() => { TbTest.Text = "Works!"; }); // WinUI 3 code. Ignore the warning: we actually DON'T want to wait for its completion!
        DispatcherQueue.TryEnqueue(() => { TbTest.Text = "Works!"; });
    }
}

Your code doesn't work in WinUI 3 because it doesn't support desktop apps. You might find this doc helpful.

Also check this answer to understand how to get the DispatcherQueue.

Sign up to request clarification or add additional context in comments.

8 Comments

THANK you! That indeed did it! I read the document you mentioned: my head is still spinning, will have to re-read it a few more times. ;-) But what really gets me is this "WinUI 3 [because it] doesn't support desktop apps" Am I really the last person on Earth to use a desktop ... and an app running on it? ;-) But again: thanks! At least my MIDI ap now works! Much obliged!
WinUI3 is indeed a desktop app. Some of the WinUI3 API doesn't support unpackaged desktop apps because package caps are needed. Also, WinUI3 doesn't support Windows Runtime APIs (WinRT), because there were not meant to be desktop-only APIs and are now "deprecated". CoreDispatcher is a Windows Runtime API, and so can only work on Windows Runtime applications, not in WinUI 3 Framework based applications.
I created a video about the DispatcherQueue.
This was great, thank you so much.
Where does that DispatcherQueue come from? It's not there in my event handler of a ViewModel class. I can add either out of two namespaces (not sure which you mean) but that leads to a compiler error.
@ygoe Pages or controls, which are DependencyObject, has DispatcherQueue property. If you need to use a DispatcherQueue in your view model, you need to do it yourself. You can see it in action on my video about the DispatcherQueue.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.