我想验证我的项目ListBox是否在UI中正确显示.我认为这样做的一种方法是遍历ListBox视觉树中的所有孩子,获取他们的文本,然后将其与我期望的文本进行比较.
这种方法的问题是内部ListBox使用a 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);
}
}
Run Code Online (Sandbox Code Playgroud)
(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 调用它(因为它受到保护),但这也没有用.
我想我知道如何做到这一点。问题是生成的项目没有添加到可视化树中。经过一番搜索,我能想到的最好的方法是VirtualizingStackPanel调用ListBox. 虽然这并不理想,但因为它仅用于测试,我想我将不得不忍受它。
这对我有用:
VirtualizingStackPanel itemsPanel = null;
FrameworkElementFactory factory = control.ItemsPanel.VisualTree;
if(null != factory)
{
// This method traverses the visual tree, searching for a control of
// the specified type and name.
itemsPanel = FindNamedDescendantOfType(control,
factory.Type, null) as VirtualizingStackPanel;
}
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;
UIElement cntr = generator.GenerateNext(out isNewlyRealized) as UIElement;
if(isNewlyRealized)
{
if(i >= itemsPanel.Children.Count)
{
itemsPanel.GetType().InvokeMember("AddInternalChild",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMember,
Type.DefaultBinder, itemsPanel,
new object[] { cntr });
}
else
{
itemsPanel.GetType().InvokeMember("InsertInternalChild",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMember,
Type.DefaultBinder, itemsPanel,
new object[] { i, cntr });
}
generator.PrepareItemContainer(cntr);
}
string itemText = GetControlText(cntr);
generatedItems.Add(itemText);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7800 次 |
| 最近记录: |