24

I am trying to port an Xamarin.Forms app to .NET MAUI but have run into the deprecation of Device.StartTimer, whilst this obviously currently still works in MAUI, I am interested to find out what the alternative is?

Currently I have a wrapper class as follows:

public void Start()
{
   if (IsRunning)
   {
      return;
   }
   var wrapper = new TaskWrapper(Task, IsRecurring, true);
   Tasks.Add(wrapper);
   Device.StartTimer(Interval, wrapper.RunTask);
}

I tried replacing this with a System.Timers.Timer however this led to the issue of not being able to modify UI elements due to being on the wrong thread? The timer wrapper itself is used in multiple places so I can't use binding for example in this case either.

Is there actually a direct replacement for Device.StartTimer? Any assistance is greatly appreciated.

2
  • i think it was replaced with IDispatcherTimer interface of IDispatcher, you have the following with that: Interval / IsRepeating / IsRunning / Tick /Start /Stop Commented Sep 22, 2022 at 14:37
  • Use MainThread to execute UI updates on the UI thread Commented Sep 22, 2022 at 14:50

5 Answers 5

45

Use Dispatcher

The Device timer is obsolete in MAUI.

You can create an IDispatcherTimer instance and subscribe to the Tick event like this:

var timer = Application.Current.Dispatcher.CreateTimer();
timer.Interval = TimeSpan.FromSeconds(1);
timer.Tick += (s,e) => DoSomething();
timer.Start();

Update UI on MainThread

Depending on the context that you're using the timer in, you may need to use the MainThread.BeginInvokeOnMainThread() method to update UI elements, which is especially important on iOS:

void DoSomething()
{
    MainThread.BeginInvokeOnMainThread(() =>
    {
        //Update view here
    });
}

More info on UI main thread:

https://learn.microsoft.com/en-us/dotnet/maui/platform-integration/appmodel/main-thread

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

5 Comments

My code works with and without BeginInvokeOnMainThread. Is it really necessary here? Microsoft talks about sensors and stuff in their article, and I'm wondering; do I have to expect errors in these cases, or what are the effects of not using this method?
I don't know anything about your code. It depends on where you create the timer and how you update your UI. Generally, you need to make sure to update the UI from the UI thread. This is a problem especially on iOS. If you don't update the UI from the UI thread, you may see exceptions and crashes.
For Xamarin back in the day it was important.
I think that due to the timer has been generated from the Applicatio Dispatcher thread (Application.Current.Dispatcher.CreateTimer), which is the UI thread, the Tick event is raised on this thread, and all the code is executed on this thread too. In other words, BeginInvokeOnMainThread is not necessary because we are already on the MainThread.
@HCAxel It depends on what else the event handler does. The event handler or any of its calls might not necessarily run on the main thread, e.g. if a thread pool thread is used by calling Task.Run(). I tried to give a general answer here, I also highlighted this in my answer.
18
IDispatcherTimer timer;

timer = Dispatcher.CreateTimer();
timer.Interval = TimeSpan.FromMilliseconds(1000);
timer.Tick += (s, e) =>
{
    label.Text = DateTime.Now.ToString();
};
timer.Start();

https://learn.microsoft.com/en-us/dotnet/maui/user-interface/controls/button#press-and-release-the-button

2 Comments

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
If you are updating a label on the UI like this, then, as mentioned by @ewerspej in their answer above, the use of BeginInvokeMainThread is recommended to ensure the update is performed on the Main (UI) thread, otherwise weird bugs and crashes may occur.
4
namespace Microsoft.Maui.Dispatching

    IDispatcherTimer timer4Registration;
    timer4Registration = Application.Current.Dispatcher.CreateTimer();
    timer4Registration.Interval = TimeSpan.FromSeconds(10);
    timer4Registration.Tick += (sender, e) => registerDeviceViaServer();
    timer4Registration.Start();enter code here

This perfectly worked for me .NET MAUI framework

Comments

1
MainThread.BeginInvokeOnMainThread(() => { Application.Current?.Dispatcher?.StartTimer(TimeSpan.FromSeconds(2), () => { doubleBackToExitPressedOnce = false; // Reset the flag after 2 seconds return false; // Stops the timer }); });

This perfectly worked for me .NET MAUI

1 Comment

I think this is the most simple replacement moving from Xamarin code. I would suggest learning how to correctly post code on StackOverflow
0

I just found that there is another documented way to create a Timer in .NET MAUI, which seems to be more precise than the one obtained using Dispatcher.CreateTimer().

var timer = new Timer(
    _ => MyTimerCallback(), // MyTimerCallback is the method you want to call for every tick
    null,
    TimeSpan.Zero,
    TimeSpan.FromMilliseconds(500);

...

private static void MyTimerCallback()
{
    Console.WriteLine("Timer event called!");
}

When you're done with the timer, you can stop it doing

timer.Dispose();

Always make sure to execute the callback in the main thread if you need to update the UI.

Here you can find the documentation for this timer.

Comments

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.