这两天在做一个 WPF 项目的时候,遇到了一个小问题。我需要更改 Listbox 中的某几行的背景颜色,那么首先我得获取到对应的 ListBoxItem,之后修改它们的 Background 属性,以实现改变背景颜色的要求。

根据官方文档中的提示,可以通过这样的方法来获取:

1
ListBoxItem lbi = (ListBoxItem)(lb.ItemContainerGenerator.ContainerFromIndex(int index));

然而在我的实际使用中,返回的 lbi 有时会是 null,这样的情况造成程序无法正确执行。该如何解决呢?

要想解决问题,必须先找到问题发生的原因:我发现在我的项目中,lb 显示出的行数是 10 行,而 lbinull 的情况恰恰发生在 index 为 11 的时候。那么是否说明不可见的 ListBoxItem 是无法被获取到的?

没错,这里涉及到了 UI 虚拟化。为了性能方面的考虑,不可见的项是不被生成的,所以当我获取超出可使范围的项时,返回的结果是 null

那么要怎样实现我预想的功能?

上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
lb.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;

private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
if (lb.ItemContainerGenerator.Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
{
MarkResult();
}
}

private void MarkResult()
{
for (int index = 0; index < range; index++)
{
ListBoxItem lbi = (ListBoxItem)lb.ItemContainerGenerator.ContainerFromIndex(index);
if (lbi != null) lbi.Background = new SolidColorBrush(Colors.DarkGray);
}
}

每当有 ListBoxItem 生成时,修改背景颜色的函数 MarkResult 会被执行,并会跳过lbinull 的情况(即 lbi 处于不可视的状态)。

实际运行下来一切顺利。