天天看点

第十九章:集合视图(六)

ObservableCollection的区别

ListView的ItemsSource属性的类型为IEnumerable。 数组实现IEnumerable接口,List和List 类也是如此。 List和List 集合特别适合ListView,因为这些类可以动态地重新分配内存以容纳几乎任何大小的集合。

您已经看到,在将集合分配给ListView的ItemsSource属性后,可以对其进行修改。 应该可以在ItemsSource引用的集合中添加项目或删除项目,并使ListView更新自身以反映这些更改。

我们来试试吧。 此ListViewLogger程序在其XAML文件中实例化ListView:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ListViewLogger.ListViewLoggerPage">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness"
                    iOS="10, 20, 10, 0"
                    Android="10, 0"
                    WinPhone="10, 0" />
    </ContentPage.Padding>
 <ListView x:Name="listView" />
</ContentPage>           

代码隐藏文件将ListView的ItemsSource属性设置为List 对象,并每秒向此集合添加一个DateTime值:

public partial class ListViewLoggerPage : ContentPage
{
    public ListViewLoggerPage()
    {
        InitializeComponent();
        List<DateTime> list = new List<DateTime>();
        listView.ItemsSource = list;
        Device.StartTimer(TimeSpan.FromSeconds(1), () =>
        {
            list.Add(DateTime.Now);
            return true;
        });
    }
}           

当你第一次运行这个程序时,似乎什么也没发生。但是,如果您将手机或模拟器侧向转动,则会显示自程序启动以来已添加到集合中的所有项目。但是在你再次转动手机的方向之前,你将不再看到它。

发生了什么?当ListView需要重绘时 - 更改手机或模拟器的方向时会出现这种情况 - 它将使用当前的IEnumerable集合。 (这是ListViewArray程序显示排序数组的方式。数组在ListView第一次显示之前已经排序。)

但是,如果ListView不需要重绘自身,则ListView无法知道何时将项添加到集合中或从集合中删除。这不是ListView的错。这真的是List类的错误。 List和List 类不实现在集合发生更改时通知ListView的通知机制。

为了说服ListView使用新添加的数据更新其显示,我们需要一个非常类似于List 的类,但它包含一个通知机制。

我们需要一个与ObservableCollection完全相同的类。

ObservableCollection是一个.NET类。它在System.Collections.ObjectModel命名空间中定义,它实现了一个名为INotifyCollectionChanged的接口,该接口在System.Collections.Specialized命名空间中定义。在实现此接口时,只要在集合中添加或删除项目,或者替换或重新排序项目时,ObservableCollection就会触发CollectionChanged事件。

ListView如何知道ObservableCollection对象被设置为其ItemsSource属性?设置ItemsSource属性后,ListView将检查设置为该属性的对象是否实现INotifyCollectionChanged。如果是这样,ListView会将CollectionChanged处理程序附加到集合以通知更改。每当集合发生更改时,ListView都会自行更新。

ObservableLogger程序与ListViewLogger程序完全相同,只是它使用ObservableCollection 而不是List 来维护集合:

public partial class ObservableLoggerPage : ContentPage
{
    public ObservableLoggerPage()
    {
        InitializeComponent();
        ObservableCollection<DateTime> list = new ObservableCollection<DateTime>();
        listView.ItemsSource = list;
        Device.StartTimer(TimeSpan.FromSeconds(1), () =>
        {
            list.Add(DateTime.Now);
            return true;
        });
    }
}           

现在ListView每秒更新一次。

当然,并非每个应用程序都需要这种功能,ObservableCollection对于那些没有这种功能的应用程序来说太过分了。 但它是多功能ListView使用的重要组成部分。

有时您将使用一组数据项,并且集合本身不会动态更改 - 换句话说,它始终包含相同的对象 - 但各个项的属性会发生变化。 ListView可以响应那种变化吗?

是的它可以,你将在本章后面看到一个例子。 启用ListView以响应各个项中的属性更改不需要ObservableCollection或INotifyCollectionChanged。 但是数据项必须实现INotifyPropertyChanged,并且ListView必须使用称为单元格的对象显示项目。

继续阅读