1

如果这个问题听起来有点笼统,我们深表歉意。我只是在寻找一些关于如何解决这个问题的一般建议:)

现在我有以下异步方法,它正在检索自定义 FileService 中的文件列表。这是在 ViewModel 的构造函数中触发的。

private async void Construct()
{
   Files = new ObservableCollection<FileViewModel>();
   IList _files = await _fileRepository.GetFiles();
   foreach (File file in _files)
   {
      Files.Add(new FileViewModel(file));
   }
}

正如您可能知道的那样,异步方法是在第一步中检索文件列表,然后将它们添加到列表(这是 UI 中的绑定源)到另一个。

对于用户来说,在异步过程完成之前他们什么都看不到,然后在一段时间后他们将立即看到所有结果。

在我看来,这违背了异步的意义,因为我真正想要的是在检索结果时添加结果。

要添加另一个步骤,我还有一个 linq 查询,它将每个文件的第一个字母拉入到类别中。这在 foreach 循环之后执行。我将如何去添加这一步呢?

非常感谢您提供的任何建议!

4

2 回答 2

2

为了做到这一点,您必须从根本上更改您的存储库。您可以返回一个在检索项目时触发事件的对象,然后在事件处理程序中将您的对象添加到您的控件绑定到的INotifyCollectionChanged接口实现中。

您还可以查看Reactive Extensions并公开一个IObservable<T>接口实现,当订阅该接口实现时,会将项目添加到数据源(同样,实现INotifyCollectionChanged)。

无论您采用哪种方法,您都必须考虑到 UI 组件只能在创建它们的线程上更新的事实,这意味着您必须编组对 UI 线程的调用。

执行此操作的最简单方法是在进行任何异步调用之前捕获SynchronizationContext使用静态Current属性,然后通过调用调用该Post方法以将项目添加到INotifyCollectionChanged实现中。

async/await并不适合在这种情况下使用;它不太适合在操作完成时发出通知,但在异步操作完成时编织延续。

不过,您可能需要重新考虑这些方法。对于大多数 LINQ 提供程序,IQueryable<T>返回 an,它派生自IEnumerable<T>. 虽然在IEnumerable<T>迭代过程中肯定会出现阻塞,但大多数提供商会以相当快的速度连续流式传输结果,但机会太快无法为您提供所需的效果。

如果 LINQ 提供程序提供它们的速度太慢(每次迭代之间的间隔很大),那么您可以使用 Reactive Framework 中的ToObservable扩展方法来启用上述模式之一,以便在您将项目放入列表中时立即为您提供抓住他们。

于 2012-10-03T00:24:25.527 回答
1

您需要更改文件存储库才能执行此操作。

我建议使用 TPL Dataflow:让文件存储库公开一个BufferBlock<File>它将开始填充的文件,并让您的代码使用它。

于 2012-10-02T21:00:20.877 回答