I want to check if the items in my ListBox are displayed correctly in the user interface. I decided that one way to do this is to go through all the children of the ListBox in the visual tree, get their text, and then compare this with what I expect from the text.
The problem with this approach is that inside the ListBox , VirtualizingStackPanel used to display its elements, so only elements that are visible are created. In the end, I came across the ItemContainerGenerator class, which seems to cause WPF to create controls in the visual tree for the specified item. Unfortunately, this causes some weird side effects for me. Here is my code for creating all the items in a ListBox :
List<string> generatedItems = new List<string>(); IItemContainerGenerator generator = this.ItemsListBox.ItemContainerGenerator; GeneratorPosition pos = generator.GeneratorPositionFromIndex(-1); using(generator.StartAt(pos, GeneratorDirection.Forward)) { bool isNewlyRealized; for(int i = 0; i < this.ItemsListBox.Items.Count; i++) { isNewlyRealized = false; DependencyObject cntr = generator.GenerateNext(out isNewlyRealized); if(isNewlyRealized) { generator.PrepareItemContainer(cntr); } string itemText = GetControlText(cntr); generatedItems.Add(itemText); } }
(I can provide the code for GetItemText() if you want, but it just traverses the visual tree until a TextBlock is found. I understand that these are other ways to have text in the element, but I will fix it as soon as I get the right one creating an item.)
In my application, an ItemsListBox contains 20 elements, of which the first 12 elements are initially visible. The text for the first 14 points is correct (probably because their controls are already created). However, for paragraphs 15-20, I do not get any text at all. Also, if I scroll to the bottom of the ItemsListBox , the text of items 15-20 is also empty. So it seems like I'm interfering with the normal WPF mechanism for generating controls in some way.
What am I doing wrong? Is there another / better way to force items to be added to ItemsControl in the visual tree?
Update . I think I found why this is happening, although I do not know how to fix it. My guess is that calling PrepareItemContainer() will generate any necessary controls to display the item, and then add the container to the visual tree in the right place. Turns out he doesn't do any of these things. The container is not added to the ItemsControl until I scroll down to view it, and at that time only the container itself is created (i.e. ListBoxItem ) - its children are not created (there should be several controls, one of which should be a TextBlock which will display the text of the element).
If I go through the visual tree of the control that I passed to PrepareItemContainer() , the results will be the same. In both cases, only ListBoxItem is created, and none of its children are created.
I could not find a good way to add ListBoxItem to the visual tree. I found VirtualizingStackPanel in the visual tree, but calling its Children.Add() InvalidOperationException (cannot add items directly to the ItemPanel , since it generates items for its ItemsControl ). Just like a test, I tried calling it AddVisualChild() with Reflection (since it is protected), but that didn't work either.