用于立即返回内容的异步方法的模式

时间:2014-01-27 19:48:55

标签: c# windows-runtime async-await c++-cx winrt-component

如果我写一个简单的函数,我可以立即得到一个结果。如果我使用async/await并返回Task - 该方法将在完成任务时返回,但如果我需要编写需要立即返回的方法,然后继续更新结果,该怎么办?并可能最终完成任务?另外,如果我想在WinRT组件库之外公开它以供其他语言的组件使用,该怎么办?我如何在C#中完成它,我将如何在C ++ / CX中完成?或JS或许?

示例1:

我想公开一个返回ImageSource的属性,这样我就可以立即将它从我的MVVM视图模型绑定到XAML视图。加载ImageSource的方法将在一个单独的类中,该类在WinRT组件外部公开(它是一个公共方法)。现在我希望该方法是可以等待的,或者至少以某种方式返回我可以等待的任务,但也立即返回ImageSource因此我调用它的属性可以立即返回,因为属性不能是异步的。调用者不知道ImageSource将是什么类型,因此它无法实例化它,因为ImageSource实际上是一种抽象类型,通常表示为BitmapImageWriteableBitmap和在我的情况下,两者都可以从方法返回。显然,方法本身会立即知道它是否会返回任何类型的对象,但是需要一些时间来读取/创建和解码图像。

我认为签名在C#中可能是这样的。

public async Task<ImageSource> GetImage(
    object key,
    out ImageSource bitmap,
    CancellationToken cancellationToken)

我根本不会等待属性访问器中方法的结果,但我想我能够立即返回位图参数,而在其他地方调用时或者我视图模型代码中的其他地方我将能够等待或取消任务。

示例2:

我希望能够列出磁盘中的文件,并在列出所有文件后获得完成的任务,但会立即返回一个IObservableVector视图模型,表示在我的XAML UI中使用的文件更新为文件以异步方式加载。

我可能会做类似的事情:

public async Task<int> GetImages(
    object queryParemeters,
    out ObservableCollection<CustomFileInfoType> files,
    CancellationToken cancellationToken)

问题

现在上面几乎看起来很好,但是我认为我不能在WinRT组件之外公开TPL任务,因为Task不是WinRT类型,所以我可能给出了一个类似上面的内部方法和一个公共的,通过调用IAsyncOperation将结果包装为AsyncInfo.Run(),传递任务和取消令牌。 ObservableCollection也只是.NET,所以我可能需要在它周围创建一个实现IObservableVector的包装器,因为我不认为它在.NET中可用。这些可能存在其他潜在问题,我不确定这种设计是否正确。

然后 - 我将如何在C ++ / CX中完成所有这些操作?还是JS?

1 个答案:

答案 0 :(得分:7)

async建立在异步操作的概念之上,具有明确的开始和结束。最后,可能会有一个结果。而已。请注意,async方法可能没有out个参数,因为它们不适合此模型。

如果您想要一个值流,请使用Reactive Extensions。有一个有趣的RxUI library很好地将可观察量与MVVM模式结合在一起。

那就是说,我不认为你的任何一个例子实际上都需要可观察的内容(尽管如果你愿意,你当然可以 移动到Rx)。我解决了您的第一个示例(数据绑定async属性)on my blog;简短的回答是使用Task<T>的包装器来实现INotifyPropertyChanged like this one

// Service
public async Task<ImageSource> GetImage(object key, CancellationToken cancellationToken);

// ViewModel
INotifyTaskCompletion<ImageSource> Image { get; private set; }
...
Image = NotifyTaskCompletion.Create(GetImage(key, token));

// View
<Image Source="{Binding Image.Result}" />

关于您的第二个示例,通过将新项目视为async方法的进度更新,可以相当轻松地完成此操作:

// Service
public async Task<int> GetImages(object queryParemeters,
    CancellationToken cancellationToken,
    IProgress<CustomFileInfoType> progress);

// ViewModel
var collection = new ObservableCollection<CustomFileInfoType>();
var progress = new Progress<CustomFileInfoType>(x => collection.Add(x));
await GetImages(query, token, progress);

完全暴露这些类型。 WinRT组件必须公开WinRT类型。我建议您使用纯async / await编写基本逻辑(服务和可能的ViewModel),然后单独进行翻译。如您所述,AsyncInfo.Run会将Task翻译为IAsyncOperation,并且ObservableCollectionIObservableVector没有内置翻译(尽管它不是'很难写,有几个可以通过谷歌。)

  

然后 - 我将如何在C ++ / CX中完成所有这些操作?还是JS?

我不知道那个。您可能必须在这些平台上为NotifyTaskCompletion编写自己的等效项,或者只使用回调。