ListView绑定数据模型却不显示

2018/4/26 13:10:40


以前使用ListView或GridView的ItemSource绑定后台模型时,就不显示结果,后来找了很久找不到原因,就不了了之了。但是最近一段时间在学使用MVVC来写软件,同时也给软件重构。再回头看看自己以前写的代码,很多数据都在页面后台文件中,看着真糟心。使用MVVC瞬间感觉分工层次清楚了很多啊有木有!但学习MVVC也有不少坑啊,今天就踩了一个,还是很简单的坑,查文档也查不到,还是自己花了好久时间试出来的。现在很兴奋的写在这里,一方面是写给未来的自己看,另一方面是分享给其他踩坑的朋友们。

其实这个坑很简单,我都怕给自己笑死,哈哈哈... 先笑一会


比如,在后台代码中有个属性:

List<Item> Items { get; set; }

前台代码ListView绑定这个属性:

                <ListView  ItemsSource="{x:Bind ShowItems,Mode=OneWay}">
                    <ListView.ItemTemplate>
                        <DataTemplate x:DataType="data:Item">
                            <Grid>
                                <!--这里是其他主要代码-->
                            </Grid>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>

看起来很简单的绑定,参考官方文档没问题,参考其他源码也没问题。但是,我的绑定就是不显示,好气啊。这个坑要么是我文档看的太少,要么是微软团队的问题吧


其实只要很简单的修改一下:

List<Item> Items { get; set; }

改成:

List<Item> Items { get; set; } = null;

一下就解决了问题。


但是,这就完了吗?不,这里还有问题。

如果你绑定的数据后来不变,这样不会有问题,但是如果你之后添加或减少List项目,则界面不会有任何变化,必须用

ObservableCollection

类,也就是:

ObservableCollection<Item> Items { get; set; } = null;

因为ObservableCollection实现了INotifyCollectionChanged, INotifyPropertyChanged这两个接口,其作用是集合项目更新时会通知界面。但我发现这样界面会出现很奇怪的问题:有时能更新,有时不能更新。

找了很久问题后才发现,第一次创建ObservableCollection对象后,界面会绑定这个对象,并根据它实时更新界面。但如果后面给Items变量重新赋值后,界面就不会更新了。如果你知道C#里引用类型(类似C++/C的指针)的话,原因其实很好懂。可以这样理解:界面会生成一个新引用,假设为_items,并引用Items引用的对象,在初始化绑定时,ObservableCollection对象会创建一个CollectionChanged事件,并且在这个事件中更新界面,以达到更新数据即更新界面的效果,可以看成现在_items已写了这个事件(我猜经编译后就是这样)。但是如果给Items变量重新赋值后,_items引用不变,但Items引用一个新变量,而这个新变量没有绑定的过程,也就是不会通知界面刷新。总之,你操作的是一个和界面无关的新变量,所以界面不会更新。

解决办法:

ObservableCollection<Item> Items { get; set; } = null;

改成:

ObservableCollection<Item> Items { get; set; } = new ObservableCollection<Item>();

并且在后续操作过程中,只给Items增加或减少项目,不要改变Items引用的目标