WPF ItemsCollection.ItemContainerGenerator可能的竞争条件

时间:2011-01-12 18:11:37

标签: c# .net wpf

在我的应用程序中,我需要在ItemsSource更改后立即获取ItemsCollection的内容。或者,至少在内容被可视化绘制之前。

我测试了以下内容:

void UserControl_Loaded(object sender, EventArgs eventArgs) {
    this.itemsControl.ItemsSource = GetItemsSource();

    int ctrIndex = 0;
    DependencyObject container;
    while((container = this.itemsControl.ItemContainerGenerator.
        ContainerFromIndex(ctrIndex++)) != null) {

        DoSomething(VisualTreeHelper.GetChild(container, 0));
    }
}

问题在于,在调用DoSomething时,VisualTreeHelper.GetChildrenCount(container)的值为0。如果稍后调用此代码 - 例如响应Button.Click事件触发,VisualTreeHelper.GetChildrenCount是预期值,代码可能会起作用。

PS。我还尝试在匿名函数中执行while循环:

this.itemsControl.ItemContainerGenerator.ItemsChanged += (_sender, _ea) => {
    int ctrIndex = 0;
    DependencyObject container;
    while((container = this.itemsControl.ItemContainerGenerator.
        ContainerFromIndex(ctrIndex++)) != null) {

        DoSomething(VisualTreeHelper.GetChild(container, 0));
    }
};

遗憾的是,行为完全相同。

修改

我无法相信你必须为生成的内容跳过多少箍。

我相信我已经找到了可以安全捕获生成的容器的最早时刻。但是,我对这些容器中生成的内容仍然没有任何意义。请注意以下事项:

this.itemsControl.ItemContainerGenerator.StatusChanged += new EventHandler(StatusChanged);

void StatusChanged(object sender, EventArgs e) {
  var cg = this.itemsControl.ItemContainerGenerator;
  if(cg.Status == GeneratorStatus.ContainersGenerated && cg.ContainerFromIndex(0) != null) {
    DoStuff();
  }
}

在调用DoStuff()时,从ContainerFromIndex返回的容器不为空。但是,VisualTreeHelper.GetChildrenCount(container)为0.我仍然非常想知道是否有人解决了这个问题。

2 个答案:

答案 0 :(得分:3)

几分钟前我遇到了同样的问题。一些小的区别是,我需要物品容器的确切位置和尺寸信息。我尝试过你试图听StatusChanged的{​​{1}}事件,最后发现当状态变为ItemContainerGenerator且容器确实生成时,它们还没有布局。

所以我做了一些非常粗暴的事情。首先,我设置了一个标记,例如ContainersGenerated,而_updatePending的状态变为ItemContainerGenerator,然后我处理了ContainersGenerated的{​​{1}}事件,会频繁开火,检查LayoutUpdated标志以及项目容器是否布局:

ItemsControl

这是残酷的,但不知何故有效。

答案 1 :(得分:0)

问题是您在更改集合时无法迭代它。解决此问题的一种方法是在填充数据后直接查看ItemsSource对象,而不是尝试迭代控件上的ItemsSource。如果您使用的是MVVVM模式,则应该能够在ViewModel中填充集合属性(绑定到控件的ItemsSource的属性),并在从数据库/服务返回数据后进行检查。