当ObservableCollection对象发生更改时,ListView不会更新

时间:2016-04-29 14:37:06

标签: wpf xaml listview xamarin.forms xamarin-studio

要自动更新Xamarin.Forms ListView的ItemsSource属性,我尝试在代码隐藏文件中使用ObservableCollection对象。然后我将ObservableCollection对象分配给ListView.ItemsSource属性。但我只是在代码隐藏文件的构造函数中执行一个赋值。

带有计时器的示例1,更新ObservableCollection对象会自动更改Xaml文件中的视图。 示例1 正如我所期望的ObservableCollection。

按下名为“Set 2”的按钮时,示例2 不起作用。 xaml文件中的视图不会随着该按钮的新数据事件处理程序在后面的代码中更新而更改。 请解释为什么示例2不起作用的原因,即使我使用与示例1中相同的ObservableCollection概念。

以下是示例1的代码按预期工作

using System;
using System.Collections.ObjectModel;
using Xamarin.Forms;

namespace ObservableLogger
{
    public partial class ObservableLoggerPage : ContentPage
    {
        public ObservableLoggerPage()
        {
            InitializeComponent();

            ObservableCollection<DateTime> list = new ObservableCollection<DateTime>();  // ObservableCollection<DateTime> object is used
            listView.ItemsSource = list; // ********** bind

            Device.StartTimer(TimeSpan.FromSeconds(1), () =>
            {
                list.Add(DateTime.Now); // *** changing the ObservableCollection<DateTime> object automatically makes ListView's ItemsSource is rebound and ListView's UI changed.
                return true;
            });
        }
    }
}

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ObservableLogger.ObservableLoggerPage">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness"
                    iOS="10, 20, 10, 0"
                    Android="10, 0"
                    WinPhone="10, 0" />
    </ContentPage.Padding>

    <ListView x:Name="listView" />
</ContentPage>

以下是我希望的不起作用的示例2的代码。当命中“Set 2”按钮时,其事件处理程序会更改ObservableCollection人员(私有字段),但ListView不会在UI中更新。

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;

namespace Mvvm1
{
    public partial class Mvvm1Page : ContentPage
    {
        private ObservableCollection<Person> _people; // private field

        public Mvvm1Page()
        {
            InitializeComponent();

            _people = getPeople(SetOption.Set1);

            listViewPeople.ItemsSource = _people; // Only one time of assigning
        }

        public void ButtonSet1OnClicked(object sender, EventArgs e)
        {
            _people = getPeople(SetOption.Set1); // *** do change the ObservableCollection<Person> but ListView is not updated in UI.
        }

        public void ButtonSet2OnClicked(object sender, EventArgs e)
        {
            _people = getPeople(SetOption.Set2); // *** do change the ObservableCollection<Person> but ListView is not updated in UI.
        }

        private ObservableCollection<Person> getPeople(SetOption op)
        {
            var list = new ObservableCollection<Person>();

            var p1 = new Person { Id = 1, Age = 19, FirstName = "Anna", LastName = "Larson" };
            var p2 = new Person { Id = 2, Age = 23, FirstName = "Beri", LastName = "Slovik" };
            var p3 = new Person { Id = 3, Age = 65, FirstName = "Ron", LastName = "Prelosi" };
            var p4 = new Person { Id = 4, Age = 32, FirstName = "William", LastName = "Maxel" };
            var p5 = new Person { Id = 5, Age = 71, FirstName = "Fred", LastName = "Lipez" };
            var p6 = new Person { Id = 6, Age = 44, FirstName = "Dave", LastName = "Vanoviz" };

            switch (op)
            {
                case SetOption.Set1:
                    list.Add(p1);
                    list.Add(p2);
                    list.Add(p3);
                    list.Add(p4);
                    break;
                case SetOption.Set2:
                    list.Add(p5);
                    list.Add(p6);
                    break;
            }

            return list;
        }
    }
}

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Mvvm1.Mvvm1Page">
  <ContentPage.Padding>
    <OnPlatform x:TypeArguments="Thickness" iOS="0,20,0,0" />
  </ContentPage.Padding>


  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*"></ColumnDefinition>
      <ColumnDefinition Width="0"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"></RowDefinition>
      <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>

    <StackLayout VerticalOptions="StartAndExpand" Orientation="Horizontal" Grid.Row="0" Grid.Column="0">
      <Button Text="Set 1" Clicked="ButtonSet1OnClicked"></Button>
      <Button Text="Set 2" Clicked="ButtonSet2OnClicked"></Button>
    </StackLayout>

    <ListView x:Name="listViewPeople" HasUnevenRows="True" Grid.Column="0" Grid.Row="1" Header="People">

      <ListView.ItemTemplate>
        <DataTemplate>
          <ViewCell>
            <ContentView Padding="5">
              <Frame OutlineColor="Accent" Padding="10">
                <StackLayout Orientation="Horizontal">
                  <StackLayout>
                    <Label Text="{Binding Id}"></Label>
                    <Label Text="{Binding FirstName}"></Label>
                    <Label Text="{Binding LastName}"></Label>
                    <Label Text="{Binding Age}"></Label>
                  </StackLayout>
                </StackLayout>
              </Frame>
            </ContentView>
          </ViewCell>
        </DataTemplate>
      </ListView.ItemTemplate>
    </ListView>
  </Grid>
</ContentPage>

using System.Text;
using System.Threading.Tasks;

namespace Mvvm1
{
    public class Person
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public int Age { get; set; }
    }

    public enum SetOption
    {
        Set1 = 1,
        Set2 = 2
    }
}

1 个答案:

答案 0 :(得分:1)

调用

_people = getPeople(SetOption.Set1);
按钮单击处理程序中的

修改现有的集合实例,而是创建一个新的集合实例,因此更改listViewPeople.ItemsSource中的项目。

每次创建新集合时,您都必须设置ItemsSource属性。那么你根本不需要本地_people变量:

public Mvvm1Page()
{
    InitializeComponent();
    listViewPeople.ItemsSource = getPeople(SetOption.Set1);
}

public void ButtonSet1OnClicked(object sender, EventArgs e)
{
    listViewPeople.ItemsSource = getPeople(SetOption.Set1);
}

public void ButtonSet2OnClicked(object sender, EventArgs e)
{
    listViewPeople.ItemsSource = getPeople(SetOption.Set2);
}

或者,您可以分配ItemsSource一次,然后在现有集合中添加和删除项目,例如, _people.Add(new Person { ... });

除此之外,listView.ItemsSource = list;不是绑定,而只是常规任务。