I want to verify that the items in my ListBox
are displayed correctly in the UI. I figured one way to do this is to go through all of the children of the ListBox
in the visual tree, get their text, and then compare that with what I expect the text to be.
The problem with this approach is that internally ListBox
uses a VirtualizingStackPanel
to display its items, so only the items that are visible are created. I eventually came across the ItemContainerGenerator
class, which looks like it should force WPF to create the controls in the visual tree for the specified item. Unfortunately, that is causing some weird side affects for me. Here is my code to generate all of the items in the 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'd like, but it just traverses the visual tree until a TextBlock
is found. I realize that ther are other ways to have text in an item, but I'll fix that up once I get item generation working properly.)
In my app, ItemsListBox
contains 20 items, with the first 12 items initially visible. The text for the first 14 items is correct (likely because their controls have already been generated). However, for items 15-20, I don't get any text at all. In addition, if I scroll to the bottom of the ItemsListBox
, the text of items 15-20 is also blank. So it seems like I'm interfering with WPF's normal mechanism for generating controls some how.
What am I doing wrong? Is there a different/better way of forcing the items in an ItemsControl
to be added to the visual tree?
Update: I think that I have found why this is occurring, although I do not know how to fix it. My assumption that the call to PrepareItemContainer()
would generate any necessary controls to display the item, and then add the container to the visual tree in the correct location. It turns out that it is not doing either of these things. The container isn't added to the ItemsControl
until I scroll down to view it, and at that time only the container itself (i.e. ListBoxItem
) is created - its children are not created (there should be a few controls added here, one of which should be the TextBlock
that will display the text of the item).
If I traverse the visual tree of the control that I passed to PrepareItemContainer()
the results are the same. In both cases only the ListBoxItem
is created, and none of its children are created.
I could not find a good way to add the ListBoxItem
to the visual tree. I found the VirtualizingStackPanel
in the visual tree, but calling its Children.Add()
results in an InvalidOperationException
(cannot add items directly to the ItemPanel
, since it generates items for its ItemsControl
). Just as a test, I tried calling its AddVisualChild()
using Reflection (since it is protected), but that didn't work, either.