如何在重新绑定后缓存TreeViewItems以重新展开?

时间:2010-06-28 19:02:23

标签: c# treeview wpf-4.0

我有一个绑定到我无法控制的集合类的TreeView。在这个类中是一个对象集合,每个对象都有自己的项集合。此层次结构固定为3深。 TreeView的子项包含在ObservableCollection中,并相应地在TreeView中更新。每个对象内部的集合都是不可观察的,因此每次向其中一个子节点添加对象时,我都必须手动将数据重新绑定到TreeView。这会导致所有已展开的子项重置为未展开状态。我正在尝试缓存已扩展的对象,以便在重新绑定后重新展开它们。孩子们按照我的预期工作,但是当我尝试扩展TreeView的孙子时,我得到一个空对象。

要获取TreeViewItem,我使用ItemsControl的ItemContainerGenerator属性:

TreeViewItem cfItem = treeView.ItemContainerGenerator
    .ContainerFromItem(obj) as TreeViewItem;
cfItem.IsExpanded = true;

第二级集合都具有对其父对象的引用。因为我有很多这样的对象,所以它们被循环并且每个都使用它的父对象来查找它的父对象的TreeViewItem。它们被添加到集合中的顺序保证(我认为)子节点将始终在父节点之后处理。因此,我得到了这条丑陋的代码:

qualItem = (
    (TreeViewItem)treeView.ItemContainerGenerator
        .ContainerFromItem(
            ((Child)obj).ParentObject
        )
    )
    .ItemContainerGenerator.ContainerFromItem(obj) as TreeViewItem;

当该行尝试从项目obj获取容器时,该行总是失败。它成功获取父TreeViewItem,但在尝试获取Child的TreeViewItem容器时,我总是收到null。文档说明ContainerFromItem()返回

  

“一个System.Windows.UIElement   对应于给定的项目。返回   如果该项不属于null,则返回null   项目集合,或者如果是   System.Windows.UIElement还没有   为它生成。“

我知道父级的项目集合中存在二级子级。我在VS 2010中检查了调试器,所有项目都在那里。我花了很多时间在谷歌搜索答案,并遇到一个人说,容器项是在后台工作线程上创建的,并且在尝试获取子项容器时可能不会生成。我试着等待ItemContainerGenerator的Status属性等于GeneratorStatus.ContainersGenerated,但我仍然得到相同的结果。我需要以某种方式为我的二级孩子获取TreeViewItem容器,这样他们就可以像第一级孩子一样重新扩展。

2 个答案:

答案 0 :(得分:0)

  

“与给定项目对应的System.Windows.UIElement。如果项目不属于项目集合,则返回null;如果尚未为其生成System.Windows.UIElement,则返回

看起来因为Virtualization,您寻找的UIElement在寻找时并不存在。如果集合不是太大,请尝试关闭Virtualization

答案 1 :(得分:0)

解决方案是在数据和TreeView之间添加另一层抽象。顶级集合是一个ObservableCollection,它包含几个ViewModel,它们实现了INotifyPropertyChanged,并且还有ObservableCollections元素位于它下面的树中。该系统允许WPF更容易地绑定和跟踪正在添加和删除的元素。

我的主要信息来源是这篇文章:

http://msdn.microsoft.com/en-us/magazine/dd419663.aspx