异步绑定和LINQ查询挂起 [英] Asynchronuos binding and LINQ query hangs

查看:182
本文介绍了异步绑定和LINQ查询挂起的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 UI 控件,该控件将Enumerable作为其绑定源.但是在设置绑定源之前,必须过滤原始的Enumerable.为此,我想使用 LINQ :

I have a UI control that takes Enumerable as its binding source. But until I set the binding source, I have to filter my original Enumerable. I would like to use LINQ for that purpose like that:

control.BindingSource = from var item in enumerable.Cast<ItemType>()
                        where item.X == 1
                        select item;

这是UI挂起的问题,因为enumerable速度很慢(例如,如果像yield return new Item(); Thread.Sleep(1000) ...这样实现),并且控件尝试在UI线程中执行查询.我试图通过结合使用Task和async-await来解决此问题:

Here is a problem that UI hangs since enumerable is slow (e.g. if implemented like yield return new Item(); Thread.Sleep(1000) ...) and control attempts to execute query in UI thread. I've tried to solve this by using a combination of Task and async-await:

control.BindingSource = await Task.Factory.StartNew(() =>
                            (from var item in enumerable.Cast<ItemType>()
                             where item.X == 1
                             select item).ToArray());

现在,UI不会挂起,但是查询执行完成后,结果立即可见.我通过在while构造中的MoveNext旁边的await中使用ObservableCollectionEnumerator来解决此问题:

Now UI doesn't hang, but results are visible at once after query execution completes. I solve this by using ObservableCollection and Enumerator with await beside MoveNext in while construct:

var source = new ObservableCollection<object>();
control.BindingSource = source;

var enumerator = enumerable.GetEnumerator();
while (await Task.Factory.StartNew(() => enumerator.MoveNext()))
{
    var item = (ItemType)enumerator.Current;

    if (item.X == 1)
        source.Add(item);
}

我正在寻找至少可以使用LINQ的解决方案. 有什么想法吗?

I'm looking for solution that will allow to use at least LINQ. Have any ideas?

推荐答案

不幸的是,async在LINQ上不能很好地发挥作用. Rx团队尝试了一个异步枚举器",但我认为它已被放弃.

Unfortunately, async doesn't play very well with LINQ. There is an "asynchronous enumerator" that the Rx team experimented with, but I believe it has been abandoned.

基于任务的异步模式确实具有用于进度报告,您可以在这里使用.

The Task-based Asynchronous Pattern does have a standard approach for progress reporting, which you can use here.

private static void EvaluateItems(IEnumerable<ItemType> items, IProgress<ItemType> progress)
{
  if (progress == null)
    return;
  var query = from var item in items where item.X == 1 select item;
  foreach (var result in query)
    progress.Report(result);
}


var source = new ObservableCollection<object>();
control.BindingSource = source;
var progress = new Progress<ItemType>(item => source.Add(item));
await Task.Run(() => EvaluateItems(enumerable.Cast<ItemType>(), progress);

基于

IProgress的代码具有更大的关注点分离. EvaluateItems方法仅与枚举和过滤项目有关.不必知道他们要进入ObservableCollection还是在WPF应用程序(Dispatcher)中运行.因此,它更具可移植性和可测试性.

IProgress-based code has greater separation of concerns. The EvaluateItems method is only concerned with enumerating and filtering the items. It doesn't have to know that they're going into an ObservableCollection or that it's running in a WPF application (Dispatcher). So it's more portable and testable.

这篇关于异步绑定和LINQ查询挂起的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆