I am trying to delay the processing of a method (SubmitQuery() in the example) called from an keyboard event in WinRT until there has been no further events for a time period (500ms in this case).
I only want SubmitQuery() to run when I think the user has finished typing.
Using the code below, I keep getting a System.Threading.Tasks.TaskCanceledException when Task.Delay(500, cancellationToken.Token); is called. What am I doing wrong here please?
CancellationTokenSource cancellationToken = new CancellationTokenSource(); private async void SearchBox_QueryChanged(SearchBox sender, SearchBoxQueryChangedEventArgs args) { cancellationToken.Cancel(); cancellationToken = new CancellationTokenSource(); await Task.Delay(500, cancellationToken.Token); if (!cancellationToken.IsCancellationRequested) { await ViewModel.SubmitQuery(); } }
The CancellationTokenSource token is used to signal that the Task should cancel itself. In the above case, the operation will just end when cancellation is requested via Cancel() method.
Task. Delay() is asynchronous. It doesn't block the current thread. You can still do other operations within current thread.
A CancellationToken enables cooperative cancellation between threads, thread pool work items, or Task objects. You create a cancellation token by instantiating a CancellationTokenSource object, which manages cancellation tokens retrieved from its CancellationTokenSource. Token property.
Delay will create a task which will complete after a time delay. Task. Delay is not blocking the calling thread so the UI will remain responsive.
If you add ContinueWith()
with an empty action, the exception isn't thrown. The exception is caught and passed to the tsk.Exception
property in the ContinueWith()
. But It saves you from writing a try/catch that uglifies your code.
await Task.Delay(500, cancellationToken.Token).ContinueWith(tsk => { });
UPDATE:
Instead of writing code to handle the exception, a boolean would be much cleaner. This is only preferred when a delay cancel is expected!. One way is to create a helper class (Although I don't like helper classes much)
namespace System.Threading.Tasks { public static class TaskDelay { public static Task<bool> Wait(TimeSpan timeout, CancellationToken token) => Task.Delay(timeout, token).ContinueWith(tsk => tsk.Exception == default); public static Task<bool> Wait(int timeoutMs, CancellationToken token) => Task.Delay(timeoutMs, token).ContinueWith(tsk => tsk.Exception == default); } }
For example:
var source = new CancellationTokenSource(); if(!await TaskDelay.Wait(2000, source.Token)) { // The Delay task was canceled. }
(don't forget to dispose the source)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With