ListBox
中的项目在UI中是否正确显示。我想到一种方法是遍历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()
(因为它是受保护的),但那也行不通。
VirtualizingStackPanel.IsVirtualizing
附加属性设置为false
,然后再将其设置为true
,当您滚动时,事情将开始虚拟化。 - Robert Macnee