Я хочу убедиться, что элементы в моем ListBox
правильно отображаются в пользовательском интерфейсе. Я решил, что один из способов сделать это - просмотреть все дочерние элементы ListBox
в визуальном дереве, получить их текст, а затем сравнить его с ожидаемым текстом.
Проблема этого подхода заключается в том, что внутренне ListBox
использует VirtualizingStackPanel
для отображения своих элементов, поэтому создаются только видимые элементы. В конце концов я наткнулся на класс ItemContainerGenerator
, который, похоже, должен заставить WPF создавать элементы управления в визуальном дереве для указанного элемента. К сожалению, это вызывает некоторые странные побочные эффекты для меня. Вот мой код для генерации всех элементов в 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);
}
}
(Я могу предоставить код для GetItemText()
, если хотите, но он просто перебирает визуальное дерево, пока не будет найден TextBlock
. Я понимаю, что есть и другие способы добавить текст в элемент, но я Я исправлю это, как только у меня получится сгенерировать элементы.)
В моем приложении ItemsListBox
содержит 20 элементов, причем первые 12 элементов изначально видны. Текст для первых 14 элементов является правильным (вероятно, потому что их элементы управления уже были созданы). Однако для пунктов 15-20 я не получаю никакого текста вообще. Кроме того, если я прокручиваю до нижней части ItemsListBox
, текст пунктов 15-20 также будет пустым. Похоже, я вмешиваюсь в обычный механизм WPF для генерации элементов управления, как-то.
Что я делаю не так? Есть ли другой / лучший способ заставить элементы из ItemsControl
быть добавленными в визуальное дерево?
Обновление : Я думаю, что я нашел, почему это происходит, хотя я не знаю, как это исправить. Я предполагаю, что вызов PrepareItemContainer()
сгенерирует все необходимые элементы управления для отображения элемента, а затем добавит контейнер в визуальное дерево в правильном месте. Оказывается, он не делает ни одну из этих вещей. Контейнер не добавляется в ItemsControl
до тех пор, пока я не прокручиваю его вниз, и в это время создается только сам контейнер (т.е. ListBoxItem
) - его дочерние элементы не создаются (здесь должно быть добавлено несколько элементов управления). , один из которых должен быть TextBlock
, который будет отображать текст элемента).
Если я перейду к визуальному дереву элемента управления, который я передал PrepareItemContainer()
, результаты будут такими же. В обоих случаях создается только ListBoxItem
, и ни один из его дочерних элементов не создается.
Я не смог найти хороший способ добавить ListBoxItem
к визуальному дереву. Я нашел VirtualizingStackPanel
в визуальном дереве, но вызов его Children.Add()
приводит к InvalidOperationException
(невозможно добавить элементы непосредственно в ItemPanel
, так как он генерирует элементы для ItemsControl
). В качестве теста я попытался вызвать его AddVisualChild()
с помощью Reflection (поскольку он защищен), но это тоже не сработало.