Possible race condition using WPF ItemsCollection.ItemContainerGenerator

In my application, I need to get the contents of the ItemsCollection right after changing the ItemsSource. Or at least before being able to visually draw content.

I checked something close to the following:

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));
    }
}

The problem is that at the point called DoSomething, the value VisualTreeHelper.GetChildrenCount(container)is equal 0. If the code is instead called at a later time - for example, in response to a triggering event Button.Click, VisualTreeHelper.GetChildrenCount- the expected value, and the code appears to be working.

PS. I also tried to loop while inside an anonymous function:

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

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

The behavior is identical, unfortunately.

change

I can’t believe how many hoops you have to jump through the generated content.

, , . , . :

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. , - .

+3
2

. , . StatusChanged ItemContainerGenerator , , , , ContainersGenerated, , .

, - . , , _updatePending, ItemContainerGenerator ContainersGenerated, LayoutUpdated ItemsControl, , _updatePending :

var firstContainer = this.ItemsContainer.ItemContainerGenerator.ContainerFromIndex(0) as FrameworkElement;
if (_updatePending 
    && firstContainer != null 
    && firstContainer.IsLoaded)
{
    // do stuff
    _updatePending = false;
}

, - .

+3

, . - ItemsSource , , ItemsSource . MVVVM, (, ItemsSource) ViewModel, , /.

0

Source: https://habr.com/ru/post/1785025/


All Articles