14.1 Delaying an action
In this section, we will experiment with three approaches for delaying an action and discuss pros and cons. We will wrap each implementation into a button causing a flashing page background after a delay of one second, so that the strategies can be compared rather easily.
Thread.Sleep – synchronousThe most trivial approach is to pause the current thread for a certain period of time, 1000 milliseconds in this example.
new Button {
Text = "Thread.Sleep",
Command = new Command(() => {
Thread.Sleep(1000);
MainPage.Animate("", x => MainPage.BackgroundColor = Color.FromRgb(x, x, x));
}),
}
,Usually, especially when triggered by a UI element like a button, the current thread is the UI thread. Consequently, the UI will freeze for one second and won’t respond to any other touch gestures. A better idea is to pause an asynchronous thread.
Thread.Sleep – asynchronousWe slightly modify the previous approach: Instead of pausing the current UI thread, we start an asynchronous task with Task.Run, which can be awaited.
new Button {
Text = "Task.Run + Thread.Sleep",
Command = new Command(async () => {
await Task.Run(() => Thread.Sleep(1000));
MainPage.Animate("", x => MainPage.BackgroundColor = Color.FromRgb(x, x, x));
}),
}
,This means that the app starts the execution, namely the one-second delay, and returns to the UI thread until the task is finished. Until then the UI remains responsive. Only after one second the app continues to execute the Command animating the page background.
Note that you might need to check whether the UI elements you want to access are still present after the delay. Since the app keeps responding to user interaction, the user might have left the current page or pressed another button.
Xamarin.Forms StartTimerA third approach we want to discuss here is based on Xamarin.Forms’ Device class. It is designed for repeating actions – as described in the following section –, but can be used for single actions as well. The StartTimer method requires two arguments: a TimeSpan and a function returning whether to continue repeating the timer. By always returning false, our function performs the desired background animation only once.
new Button {
Text = "Device.StartTimer",
Command = new Command(() => Device.StartTimer(
TimeSpan.FromSeconds(1),
() => {
MainPage.Animate("", x => MainPage.BackgroundColor = Color.FromRgb(x, x, x));
return false;
})),
}
,This solution is comparable with the previous one, since the UI thread is not blocked and the app remains responsive.