miechooy
miechooy

Reputation: 3422

TaskCompletionSource with Token

I have created scan method using Scandit framework. Since I am using Xamarin.Forms there is no option to await the scan. Scandit prepared the callback as result of scanning. I would like to wrap that into one method which could be used with awaiter.

There is what I have done:

 public async Task<Operation<string>> ScanAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            try
            {
                _codeScannedTcs = new TaskCompletionSource<Operation<string>>();
                ScanditService.BarcodePicker.DidScan += OnScanFinished;

                await ScanditService.BarcodePicker.StartScanningAsync();

                var result = await Task.WhenAny(_codeScannedTcs.Task);

                return result.Result;
            }
            catch (TaskCanceledException)
            {
                return Operation<string>.FailedOperation("A task was canceled");
            }
            catch (Exception ex)
            {
                return Operation<string>.FailedOperation(ex.Message);
            }
            finally
            {
                _codeScannedTcs = null;
                ScanditService.BarcodePicker.DidScan -= OnScanFinished;
            }

        }

How in that situation I can use the cancellation token to break the scanning in any time?

Upvotes: 0

Views: 144

Answers (1)

Dan
Dan

Reputation: 883

I've used this code in the past:

        /// <summary>
    /// Allows the code waiting for an async operation to stop waiting when the cancellation token is set.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="task"></param>
    /// <param name="cancellationToken"></param>
    /// <see cref="https://blogs.msdn.microsoft.com/pfxteam/2012/10/05/how-do-i-cancel-non-cancelable-async-operations/"/>
    /// <returns></returns>
    public static async Task<T> WithCancellation<T>(this Task<T> task, CancellationToken cancellationToken)
    {
        var tcs = new TaskCompletionSource<bool>();

        using (cancellationToken.Register(x => ((TaskCompletionSource<bool>)x).TrySetResult(true), tcs))
        {
            if (task != await Task.WhenAny(task, tcs.Task))
                throw new OperationCanceledException(cancellationToken);
        }

        return await task;
    }

It is either verbatim copy pasted from a microsoft blog post or derivative of it

Upvotes: 1

Related Questions