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

Fil*_*kun 4 c# async-await windows-runtime 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)
Run Code Online (Sandbox Code Playgroud)

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

例2:

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

在这里,我可能会做类似的事情:

public async Task<int> GetImages(
    object queryParemeters,
    out ObservableCollection<CustomFileInfoType> files,
    CancellationToken cancellationToken)
Run Code Online (Sandbox Code Playgroud)

问题

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

那么 - 我将如何在C++/CX中完成所有这些工作?还是JS?

Ste*_*ary 7

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

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

也就是说,我认为你的任何一个例子都不需要观察(尽管如果你愿意,你当然可以转移到Rx).我在我的博客上解决了你的第一个例子(数据绑定async属性); 简短的回答是使用这个实现的包装器,如下所示:Task<T>INotifyPropertyChanged

// 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}" />
Run Code Online (Sandbox Code Playgroud)

关于您的第二个示例,通过将新项目视为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);
Run Code Online (Sandbox Code Playgroud)

暴露这些类型完全是另一回事.WinRT组件必须公开WinRT类型.我建议您使用pure async/ 编写基本逻辑(服务和可能的ViewModel)await,然后单独进行翻译.正如你提到的,AsyncInfo.Run将转化TaskIAsyncOperation,并没有一个内置的翻译人员ObservableCollectionIObservableVector(尽管它并不难写,而且有几个可用通过谷歌).

那么 - 我将如何在C++/CX中完成所有这些工作?还是JS?

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