将对象绑定到ListBox,Items状态与预期不符

最近看discussion,有个话题比较有意思:
定义了一个类

    class DisplayedItem
    {
 
        public DisplayedItem(string name, bool isChecked)
        {
            Name = name;
            IsChecked = isChecked;
        }
        public string Name { get; set; }
        public bool IsChecked { get; set; }
    }
这个类有一个IsChecked的bool类型,想把这个对象集合绑到ListBox,每个ListBoxItem显示为CheckBox。 
    ObservableCollection<DisplayedItem> col = new ObservableCollection<DisplayedItem>();
    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        col.Add(new DisplayedItem("item1", false));
        col.Add(new DisplayedItem("item2", false));
        col.Add(new DisplayedItem("item3", false));
        col.Add(new DisplayedItem("item4", false));
        col.Add(new DisplayedItem("item5", false));
        col.Add(new DisplayedItem("item6", false));
        col.Add(new DisplayedItem("item7", false));
        col.Add(new DisplayedItem("item8", false));
        col.Add(new DisplayedItem("item9", false));
        col.Add(new DisplayedItem("item10", false));
        col.Add(new DisplayedItem("item11", false));
        col.Add(new DisplayedItem("item12", false));
        col.Add(new DisplayedItem("item13", false));
        col.Add(new DisplayedItem("item14", false));
        col.Add(new DisplayedItem("item15", false));
        col.Add(new DisplayedItem("item16", false));
 
        listBox1.ItemsSource = col;
    }
<ListBox Name="listBox1" Margin="198,12,0,48" HorizontalAlignment="Left" Width="146" Height="120">
        <ListBox.ItemTemplate>
           <DataTemplate>
               <CheckBox Content="{Binding Path=Name}" 
                         IsChecked="{Binding Path=IsChecked, Mode=TwoWay}"/>
           </DataTemplate>
        </ListBox.ItemTemplate>
</ListBox>
 

界面上有个Button,点击时把所有CheckBox都勾上

private void button1_Click(object sender, RoutedEventArgs e)
{
    foreach (var item in col)
    {
       item.IsChecked = true;
    }
}

运行后的实际结果却很奇怪

初始:
image

                                                     图1

点击Button后,把滚动条拉到最下,会发现item10到item16都勾上了,而item1到item9却没勾上。

clip_image002

                                                    图2

调试时可发现,实际绑定的对象的IsChecked都是true。

研究一下代码,点Button让所有item都勾上,这个很好实现,只要DisplayedItem实现INotifyPropertyChanged。可以参见这里的绑定到.net属性/对象这节。

 

但是我不禁要问为什么不实现INotifyPropertyChanged的情况下为什么有的是勾上的,有的却不勾上,而且怪异的是,在点Button前,先把滚动条拉到最下,再点Button,会发现所有items都没有勾上:
clip_image002[5]

                                                     图3

这么怪异的不可思议的匪夷所思的事情是怎么发生的,是WPF有bug吗?

幸好有高人回复,经过我的理解大意如下:

因为没有实现INotifyPropertyChanged,绑定到ListBox时使用了OneTime这种模式。可以看到ListBox中,有些Item(Item1到Item7)是在初始状态就显示的,有些(Item8到Item16)是不显示的。对于已经显示的,在显示时使用OneTime去计算值,都是false,对于未显示的,为了性能上的考虑,在没显示时不作绑定的计算。在点击Button时,源中已经都是true了,把滚动条拉到最下,有个显示的过程,这时经过计算得到true,所以UI上会勾上。如果先把滚动条拉到最下,所有的Item都经过OneTime的计算,值都是false,点击button,虽然源已经被设置为true,但是没有实现INotifyPropertyChanged所以源的改变不会显示在UI上。

确实是这样的,对于使用了OneTime这点可以通过把Item6,Item7的初始状态设为true,可以观察的到。
image

                           图4 ListBox加高后,初始Item6,Item7设为true

但是细心的同学会发现初始情况下Item8,Item9也是不显示的,为什么点击button后,还是没勾上呢?

这个确实奇怪,又有高人路过,出招了:
为了使得显示的流畅感十足,WPF为对某几个未显示的(接近已显示的)也作了绑定计算,这里是Item8和Item9。

我作了实验,把ListBox的高度加大,确实原先勾上的就不勾上了:

image

                        图5 加高后,Item12,Item13处于未勾中状态

 

 

真相只有一个。

转载于:https://www.cnblogs.com/iwteih/archive/2010/02/14/1668202.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值