最近在使用windows phone 中Listbox的过程中,发现了一个ListBox的bug
场景模拟:
有一个用于绑定的Person 类
public class Person
{ public string Name { get; set; }public bool Female { get; set; }
}页面上有一个ListBox
<ListBox x:Name="lst" ItemsSource="{ Binding}" ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{ Binding Name}"/> <CheckBox IsChecked="{ Binding Female}" Content="Female"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
在page的loaded事件给ListBox添加200条数据
List<Person> Persons = new List<Person>();
void MainPage_Loaded(object sender, RoutedEventArgs e)
{ for (int i = 0; i < 200; i++) { Person person = new Person(); person.Name = string.Format("name:{0}", i.ToString()); person.Female = false;Persons.Add(person);
}lst.DataContext = Persons;
}运行app,勾选前面6个CheckBox,向下滑动ListBox,会发现下面断断续续的也勾选了Checkbox,刚开始以为是我的绑定写的有问题,勾选一个导致多个CheckBox勾选,后来通过加断点监测,我选中一个CheckBox,只会触发一次CheckBox的Checked事件,但是往下滑动的时候还会勾选多个,于是怀疑是ListBox的问题,当ListBox的项较多时,ListBox会启用一种叫做虚拟化的机制,把虚拟化去掉试试:
<ListBox x:Name="lst" ItemsSource="{ Binding}" ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListBox.ItemsPanel> <ItemsPanelTemplate> <StackPanel/> </ItemsPanelTemplate> </ListBox.ItemsPanel> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{ Binding Name}"/> <CheckBox IsChecked="{ Binding Female}" Content="Female"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox>虚拟化去掉之后就ok了,但是问题又来了,由于在我的app中有几百个item,ListBox需要把每个Item渲染完才显示,所以会很慢,而且内存达到了200多M,很显然去掉虚拟化不可取,难道只能手动写延迟加载吗?为了一个这个小的功能单独写一个控件得不偿失,于是继续试验,偶然发现如果CheckBox的IsChecked属性采用的绑定模式是双向绑定则ok
<ListBox.ItemTemplate>
<DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{ Binding Name}"/> <CheckBox IsChecked="{ Binding Female,Mode=TwoWay}" Content="Female"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate>这样可以解决选中一个多个CheckBox选中的情况,好吧,问题初步解决了,在我的app中,我回到上一页,然后又进入这一页,又出现了一个奇怪问题(我把选中项的状态保存到本地,每次进该列表的时候会读取相应设置,初始化列表状态),选中的项出现了错乱,而且规律不一定,难道是我的代码真出问题了。我给CheckBox添加了Checked,UnChecked事件,发现我在向下滑动ListBox的过程中会不规律的触发CheckBox的Checked,UnChecked事件,但是在这个过程中我并没有点击任何CheckBox,难道ListBox真不ok吗?嗯,同事一句话提醒了我,可以用CheckBox的Click事件试一下,我把本来要在Checked,UnChecked事件处理的事件拿出来放到Click事件处理
private void CheckedHandler()
{}
private void UnCheckBoxHandler()
{}
private void CheckBox_Click(object sender, RoutedEventArgs e)
{ CheckBox checkBox = sender as CheckBox; if (checkBox != null) { if (checkBox.IsChecked.Value) CheckedHandler(); else UnCheckBoxHandler(); } }
到这里,才把所有的问题解决到。
关于这个问题的原因我只是猜测了一些原因,由于没有官方文档,就不献丑了。不知道微软能不能修正ListBox的这个Bug。
demo下载地址: