6

I'm trying to update the Text of a TextBlock every time a timer fires. Here is my code:

public static DateTime startTime;
System.Timers.Timer timer = new System.Timers.Timer(1000);
timer.AutoReset = true;
timer.Elapsed += Timer_Tick;
timer.Start();

private void Timer_Tick(object sender, EventArgs e)
{
    timerLabel.Text = DateTime.Now.Subtract(startTime).ToString(@"hh\:mm\:ss");
}

When I run it I get Exception thrown: 'System.Runtime.InteropServices.COMException' in WinRT.Runtime.dll. All other code I put in that function will run, it just won't update the text of my TextBlock. I've also tried with a System.Threading.Timer and get the same error.

How can I fix this to update the Text of my TextBlock every time a second elapses? Every answer I find doesn't seem to work with WinUI 3.

Ricky Kresslein
  • 372
  • 1
  • 13
  • 1
    Try `DispatcherQueue.TryEnqueue(() => { timerLabel.Text = DateTime.Now.Subtract(startTime).ToString(@"hh\:mm\:ss"); } );` in `Timer_Tick` instead – Simon Mourier Jun 21 '22 at 16:58
  • @SimonMourier Yes, that worked! Thank you! I had tried `Dispatcher.Invoke(new Action(() =>` but that doesn't seem to work anymore with WinUI 3. Your code solved it. If you add that as an answer I will accept it. – Ricky Kresslein Jun 22 '22 at 01:32

1 Answers1

3

A timer from System.Timers will tick on a non-UI thread, so you must use a Microsoft.UI.Dispatching.DispatcherQueue somehow.

You can use the one on the current Window or get one from the current thread (if it has a dispatcher queue) using the DispatcherQueue.GetForCurrentThread method.

Then your code can be written like this:

private void Timer_Tick(object sender, EventArgs e) => DispatcherQueue.TryEnqueue(() =>
{
    timerLabel.Text = DateTime.Now.Subtract(startTime).ToString(@"hh\:mm\:ss");
});

Note that you can also use a timer provided by the DispatcherQueue itself with the DispatcherQueue.CreateTimer Method which will automatically tick in the proper thread.

Simon Mourier
  • 132,049
  • 21
  • 248
  • 298