4

If I write a simple function I can get a result immediately. If I use async/await and return a Task - the method will kinda return when it's done with the task, but what if I need to write a method that needs to return immediately, but then continue updating the result and potentially eventually complete the task? Also what if I want to expose it outside a WinRT Component library for consumption in components in other languages? How would I do it in C# and how would I do it in C++/CX? Or JS perhaps?

Example 1:

I want to expose a property that returns an ImageSource so I can immediately bind it from my MVVM view model to the XAML view. The method to load the ImageSource is going to be in a separate class that is exposed outside a WinRT Component (it is a public method). Now I want that method to be awaitable, or at least somehow return a task I can await but also immediately return the ImageSource so the property I call it from can immediately return since properties can't be async. The caller doesn't know what type the ImageSource will be so it cannot instantiate it since ImageSource is virtually an abstract type and is typically represented as a BitmapImage or WriteableBitmap and in my case both can be returned from the method. Obviously the method itself immediately knows whether it is going to return either of the types of objects, but it takes some time to read/create and or decode the image.

I'm thinking the signature might be something like this in C#

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

and I would simply not await the result of the method in the property accessor, but I'm thinking I'll be able to return the bitmap argument immediately, while when called elsewhere or event elsewhere in the code of my view model I'll be able to await or cancel the task.

Example 2:

I want to be able to list files from a disk and get a task that is complete when all files have been listed, but immediately return an IObservableVector of view models representing the files for use in my XAML UI that updates as pages of the files are loaded asynchronously.

Here I would probably do something similar:

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

Problems

Now the above look almost good, but I don't think I can expose a TPL Task outside a WinRT Component since Task is not a WinRT type, so I'd probably gave an internal method like the above and a public one that wraps the result as an IAsyncOperation by calling AsyncInfo.Run(), passing the task and cancellation token. ObservableCollection is also .NET only, so I'd probably need to create a wrapper around it that implements an IObservableVector since I don't think one is available in .NET. There are probably other potential problems with those and I am not sure if this design is right.

Then also - how would I do all this in C++/CX? Or JS?

4

1 回答 1

7

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

如果您想要一个值流,请使用Reactive Extensions。有一个有趣的RxUI 库,它很好地将 observables 与 MVVM 模式结合起来。

也就是说,我认为您的任何一个示例实际上都不需要 observables(尽管如果您愿意,您当然可以转移到 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}" />

关于您的第二个示例,这可以通过将新项目视为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我建议您使用纯/编写基本逻辑(服务和可能的 ViewModel)await,然后单独进行翻译。正如您所指出的,AsyncInfo.Run将翻译Task为,并且没有用于toIAsyncOperation的内置翻译器(尽管它不难编写,并且有几个可通过 Google 获得)。ObservableCollectionIObservableVector

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

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

于 2014-01-27T20:41:12.873 回答