I am using an asynchronous operation that completes in three steps, returning partial results before completion. Originally it's using events to signal progress, and I want to wrap it properly as an await
able operation (or a chain of them).
To be exact, it's the PhotoCamera.CaptureImage method in Windows Phone 7, which fires events in the following order (with relevant result types):
CaptureStarted
, not that interesting to meCaptureThumbnailAvailable
(Stream)CaptureImageAvailable
(Stream)CaptureCompleted
(bool)How to wrap this? Currently I'm using a TaskCompletionSource
and calling SetResult
on CaptureCompleted
. It does not address steps 2 and 3, the thumbnail and image becoming available. I decided to use callbacks for those instead.
My extension method (leaving out the code for brevity):
public static Task<bool> CaptureImageAsync(this PhotoCamera photoCamera,
Action<Stream> thumbnailAvailableCallback,
Action<Stream> imageAvailableCallback)
This doesn't feel entirely clean, a mixture of Tasks and callbacks. I know of IProgress<T>
. However, the progress values aren't of uniform type (Stream, Stream, bool)... and wouldn't that stretch the IProgress<T>
pattern too far?
Using multiple Task<T>
that are awaited in order is an option, but that supposes a specific order that I'd also have to enforce somehow. Maybe each task result could contain the "next" task as a member:
ThumbnailResult thumbnailResult = await photoCamera.CaptureImageAsync();
...
ImageResult imageResult = await thumbnailResult.NextTask;
...
bool finalResult = await imageResult.NextTask;
I still think that I'm somewhat off the mark here. Ideas?
Personally i'll create a class for it with 3 methods returning Task<T>
. The caller will be able to call the 3 methods in any order he wants and it'll always work. if GetFinalResultAsync
is called first and then GetThumbnailAsync
then only consequence is that the second Task<T>
will aready have a result when await is used and it will return synchronously.
var photoCapture = photoCamera.BeginCapture();
var thumbnailResult = await photoCapture.GetThumbnailAsync();
var imageResult = await photoCapture.GetImageAsync();
var finalResult = await photoCapture.GetFinalResultAsync();
To wait for everything :
var thumbnailTask = photoCapture.GetThumbnailAsync();
var imageTask = photoCapture.GetImageAsync();
var finalTask = photoCapture.GetFinalResultAsync();
await Task.WhenAll(thumbnailTask, imageTask, finalTask);
DoWork(thumbnailTask.Result, imageTask.Result, finalTask.Result);