Calling an asynchronous method multiple times

I have a WPF application where one of the properties in the viewmodel will be populated as a service call. So far, I have followed Stephen Cleary's excellent tutorials. He discusses one way to do it here

In my case, the view model is created once per application. The application calls the Initialise method (a custom method) on the view model, passing in some information, based on which it is expected that the View model will call the service to get the instantiated property.

The problem is that the application can call the Initialise method multiple times (the user moves randomly), passing in a new set of information. When this happens, I need to discard previously started tasks (if any) that were called in the previous time when Initialization was called, call the service with a fresh set of information, and make sure the property is only associated with the result of the last call.

Can anyone help come up with a pattern to achieve this? Basically they call the asynchronous parse method multiple times, but only keep the last result.

+3


source to share


1 answer


Basically, you want to cancel the previous method call Initialize

. And in TPL, if you want to undo something, you usually have to use CancellationToken

.

How you could do this is to have a type type CancellationTokenSource

in your viewmodel representing the cancellation of the last call Initialize

. When you run Initialize

it cancels the previous call, sets its own cancellation, calls the service, and then only sets the property if no cancellation was requested. In code:



class ViewModel
{
    // default value just to avoid a null check
    private CancellationTokenSource intializationCancellation =
        new CancellationTokenSource();

    public async Task InitializeAsync(int parameter)
    {
        // cancel previous initialization, if any
        intializationCancellation.Cancel();

        var cts = new CancellationTokenSource();
        intializationCancellation = cts;

        var value = await GetValueaAsync(parameter);

        if (cts.Token.IsCancellationRequested)
            return;

        Value = value;
    }

    private async Task<string> GetValueAsync(int parameter)
    {
        // call the external service here
    }

    public string Value { get; private set; }
}

      

If the service you are calling supports cancellation, you must pass to it as well CancellationToken

, which may save some resources. If you do, don't forget to catch the one received OperationCanceledException

(as I believe you don't want to be Initialize

thrown, even if canceled).

+1


source







All Articles