【问题标题】:Cannot populate object hierarchy when using Reactive extensions使用反应式扩展时无法填充对象层次结构
【发布时间】:2012-03-20 16:34:58
【问题描述】:

我是响应式扩展的新手,所以我不知道在问题中描述什么是重要的。

我有 WPF 应用程序,它在 treeView 中显示 5 层的层次结构。该架构使用 Prism 和 MVVM。为 treeView 构建源数据的代码需要大约一分钟来构建三个顶级节点的对象层次结构。以下是我的 MVVM 的一些细节:

  private ObservableCollection<IDxStudioInstanceDto> _instanceList = null;
  public ObservableCollection<IDxStudioInstanceDto> InstanceList {
     get { return _instanceList; }
     set {
        _instanceList = value;
        OnPropertyChanged("InstanceList");
     }

  private void DisplayDataFetch() {
     InstanceList = _businessFacade.InstanceListFetch();

     //foreach(var instance in InstanceList) {
     //   _businessFacade.InstanceHierarchyFetch(instance);
     //}

     var query = from instance in InstanceList
                 select instance;
     var observableSequence = query.ToObservable().SubscribeOn(Scheduler.TaskPool).ObserveOnDispatcher();
     _subscribeInstanceHierarchy = observableSequence.Subscribe(instance => _businessFacade.InstanceHierarchyFetch(instance));
  }

名为“DisplayDataFetch”的 MVVM 方法做了两件事。它仅将顶级节点加载到 ObservableCollection 中。

     InstanceList = _businessFacade.InstanceListFetch();

剩余的代码,无论是注释的 foreach 循环还是下面的响应式扩展代码,都用子层次结构填充每个顶级节点。两者都使用相同的调用集来构建层次结构。我希望能够使用顶级节点快速加载 treeView,然后在完成剩余的子层次结构后,将其添加到显示的 treeView 中。

如果我通过用带注释的 foreach 循环替换响应式扩展代码来在 UI 线程上运行整个过程,则 treeView 会按预期显示层次结构。虽然 UI 线程被阻塞了大约一分钟。

如果我运行响应式扩展代码,UI 线程会被阻塞大约一分钟,树的顶级节点是“裸露的”,缺少整个子层次结构。

我尝试了 Scheduler.ThreadPool 并删除了 observableSequence 的 ObserveOnDispatch() 部分,但没有成功。

有什么想法吗?

【问题讨论】:

  • 我解决了“裸”顶级节点的问题。在某些子对象上缺少 INotifyPropertyChanged 是一个错误。现在它在完成处理时显示完整的树。但是,它仍然会阻塞 UI 线程,直到完成。顶级节点的初始列表在可用时不显示,然后在处理结束时所有内容都突然出现在表单上,​​完全形成。我期待显示顶级节点的初始列表,然后在每个线程上完成处理时填写。我没有正确实现 SubscribeOn 和 ObserveOnDispatch 吗?
  • 顶级节点初始列表的显示现在可以正常工作,这是一个检测问题。在为每个顶级节点填充子节点时,UI 仍会阻塞大约一分钟。所有顶级节点都是裸节点,直到所有的子节点处理完成,然后它们都一起显示。为什么他们不在每个完成时填写?

标签: wpf prism system.reactive


【解决方案1】:

UI 被阻止,因为您的观察者/订阅者 (instance =&gt; _businessFacade.InstanceHierarchyFetch(instance)) 正在调度程序上运行。

我建议您重构 InstanceHierarchyFetch 以返回结果,而不是改变传入的 IDxStudioInstanceDto 实例。然后您可以将查询更改为如下内容:

var query = from instance in InstanceList.ObserveOn(Scheduler.TaskPool)
            let hierarchy = FetchHierarchyFor(instance.Key)
            select new {instance, hierarchy};

query
  .ObserveOnDispatcher()
  .Subscribe(tuple => tuple.instance.UpdateHierarchy(tuple.hierarchy);

这样,获取将在后台线程中运行,而您的实例的变异将在 UI 线程中运行,以便与 WPF 和您的数据绑定配合使用。

关于原始代码的几点注意事项:

  • SubscribeOn 没有做你认为的事情。阅读它。你想用的是ObserveOn
  • {from instance in InstanceList select instance} 等价于 {InstanceList}。这是多余的。

【讨论】:

  • 感谢您的信息,我会调查所有这些。
  • 甜...!谢谢。使用您的答案使我在使用 Rx 的道路上走得更远。
猜你喜欢
  • 1970-01-01
  • 2012-08-06
  • 1970-01-01
  • 2015-12-10
  • 1970-01-01
  • 1970-01-01
  • 2011-03-21
  • 2016-08-26
相关资源
最近更新 更多