WPF MVVM Treeview异步加载任务

时间:2011-03-10 14:46:01

标签: wpf treeview

我有一个使用MVVM的WPF应用程序,它利用TreeViewItemViewModels简化了使用树视图的工作,如Josh Smith http://www.codeproject.com/KB/WPF/TreeViewWithViewModel.aspx

所示

我的treeview表示关系数据库中的记录,每个节点都按需加载其子节点。为了提高UI的响应能力,我一直在尝试使用.net 4.0中的任务异步加载数据,但我很难令人满意地实现这一点。

treeviewitemviewmodel IsExpanded属性如下所示:

public bool IsExpanded
{
  get { return _isExpanded; }
  set
  {        
    if (_isExpanded == value)
      return;

    if (!_isSelected)       
      IsSelected = true;

    _isExpanded = value;

    if (_isExpanded &&
        _parent != null &&
        _parent.GetType() != typeof(FirstGenerationViewModel))
      _parent.IsExpanded = true;

    ApplicationSetup.Messenger.NotifyColleagues(ApplicationSetup.MSG_WORKING, true);

    Task task = Task.Factory.StartNew(() =>
    {
      LoadChildren();
    })
    .ContinueWith((t) => 
      {
        this.OnPropertyChanged("IsExpanded");
        ApplicationSetup.Messenger.NotifyColleagues(ApplicationSetup.MSG_WORKING, false);            
      }, ApplicationSetup.UIScheduler);        
  }
}

如果我手动选择项目并展开和折叠它们都按预期工作 - 显示工作动画,同时执行LoadChildren(),然后在调用OnPropertyChanged并关闭动画时展开项目。

但是,我正在尝试实现搜索功能。如果已加载记录,我只需迭代树视图直到找到它,然后选择它。但是,如果未加载,则进程应在数据库中搜索记录然后显示它。当记录按需加载时,进程从数据库中获取所需项目及其祖先,并尝试依次扩展每个祖先,然后最终选择所需项目:

      foreach (var item in ancestors.Keys)
      {            
        TreeViewItemViewModel tv = _fgvm.recordsViewHelper.GetTreeViewItem(new ItemArgs 
                                                                            { 
                                                                              TargetTableName = item, 
                                                                              TargetPk = ancandtarget[item]
                                                                            });

        tv.IsExpanded = true;            
      }

如果所寻求的项目在层次结构中很高,则可行。但是,当记录嵌套了几个项目时,tv为空。我认为这是因为在_fgvm.recordsViewHelper.GetTreeViewItem尝试在树视图中找到它之前,项目尚未加载。

我怎样才能做到这一点?我尝试过使用Wait()但似乎冻结了UI。

1 个答案:

答案 0 :(得分:0)

我自己解决了这个问题。真的很明显。我现在使用包装器方法来扩展foreach循环中的祖先,它返回IsExpanded属性使用的任务。然后,此任务可以调用Wait(),以确保下一个祖先的父级在继续之前完全加载。