是否可以?如何?
我有一个异步方法从数据库中获取数据行。我的结果是IAsyncEnumerable<TItem>. 它应该是快速响应 UI 的完美数据类型,但是,当我将其设置为网格的数据源时,它不起作用并且不显示任何内容。
我对此有两个解决方法。首先显然是从我的异步任务返回数组。第二个是类似的 - 我可以只使用ToArrayAsync()结果(来自System.Linq.Async)。
我怀疑使用ToArrayAsync()比仅从任务返回数组慢,所以它没有多大意义。
IAsyncEnumerable如果类型可以直接用作控件的数据源,那就很有意义了。但随后我可能需要实现某种IObservable接口或类似的东西。有人试过这个吗?
整个事情是相当新的,我找不到任何例子,甚至找不到一篇文章表明这是可能的。我的意思是 -IAsyncEnumerable如果你不能将它用于 UI 有什么好处?
IAsyncEnumerable<TItem>更新:我正在寻找的是和之间的转换ObservableCollection<TItem>。我找到了示例,但它们的工作方式与我提到的解决方法完全相同 - 因此数据被放入数组中,然后添加到集合中。这破坏了所有IAsyncEnumerable<T>好处。
IAsyncEnumerable引入是为了允许异步数据生成器/数据流。ItemsControl通常,像显示数据项集合这样的控件是基于索引的。并ICollectionView立足。
ICollectionView通常,控件通过原始集合获取项目。数据项由其在源集合中的索引标识ICollectionView,被包装到UIElement容器中进行渲染。
数据流/生成器不是基于索引的。Enumerator( 调用的结果)IEnumerable.GetEnumerator用于通过调用IEnumerator.MoveNext(foreach是一种语言构造,为了方便起见,封装了涉及 的实际枚举逻辑IEnumerator) 来从一个元素步进到另一个元素。
除了异步数据流引入的潜在线程问题之外,基于索引的ItemsControl需要提前知道它的所有项目 - 这就是为什么你需要一个实现的集合INotifyCollectionChanged以便在更改时ItemsControl更新它Items:视图被认为是被动的 -它只显示数据,不生成数据。
虽然不是强制性的,但 WPF 在设计时就考虑到了 MVVM。活动部分通常是模型或视图模型。数据生成通常发生在模型中。因此,拥有直接绑定源是没有意义的,IAsyncEnumerable因为这意味着被动 UI 元素必须直接生成/使用数据流。您可能希望这是 View Model/ 的责任Binding.Source。再说一次,UI 设计为适用于ICollectionView实现,而不是直接适用于集合及其迭代器。
您可以做的是枚举IAsyncEnumerable并使用生成的结果Binding.Source更新 an :ObservableCollection
public ObservableCollection<DataItem> ItemsSourceForDataGrid { get; }
private async Task GenerateDataItemsAsync(IAsyncEnumerable asyncDataStream)
{
// Keep the GUI responsive while consuming an e.g. CPU intensive generator
await foreach (DataItem item in asyncDataStream)
{
this.ItemsSourceForDataGrid.Add(item);
}
}
Run Code Online (Sandbox Code Playgroud)
ToListAsync另请注意,诸如和 之类的扩展方法ToArrayAsync可能会锁定应用程序。如果您不知道数据源(即生成器),则在ToListAsync尝试最终确定数据流时可能会锁定应用程序。但根据定义,数据流可以是无限的,这将导致ToListAsync永远不会返回或完成返回的Task对象。如果您发现自己需要ToArrayAsync并且您是数据生成器的作者,那么您可能不应该IAsyncEnumerable首先使用。异步终结器就像ToArrayAsync藐视IAsyncEnumerable.