2016-04-29 118 views
1

要自动更新Xamarin.Forms ListView的ItemsSource属性,我尝试在代码隐藏文件中使用ObservableCollection对象。然后,我将该ObservableCollection对象分配给ListView.ItemsSource属性。但是我只是在代码隐藏文件的构造函数中完成一项任务。当ObservableCollection对象发生变化时,ListView不会更新

例1用一个计时器,更新ObservableCollection对象会自动更改Xaml文件中的视图。 正如我期望的那样,示例1的作品使用了ObservableCollection。

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

在下面是实施例1的代码的工作,因为我希望例2不工作的原因。

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

在按钮单击处理程序调用

_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;是没有约束力的,但只是一个普通的任务。

+0

谢谢您的回复。在示例1中,因为ObservableCollection列表对象不是新的列表对象,而是现有列表对象(已连接到listView.ItemsSource),并且它在Device.StarTimer()的回调中使用新的DateTime条目进行了扩展。 , 真的吗? –

+0

对于示例2还有一件事,如果我不想在后台代码中将对象的集合明确分配给listView.ItemsSource,那么我可以在后端使用ViewModel(其一些公共属性字段作为对象的集合),并且那么我怎样才能在Xaml文件中将ViewModel绑定到listView的ItemsSource? –

+0

你的第一个评论:是的,这是真的(并已在答案中解释)。对于第二种:您将拥有一个视图模型类,其中包含实现INotifyPropertyChanged接口的Items属性(类型为ObservableCollection ),并在Items属性更改时触发PropertyChanged,即设置为新集合实例时触发PropertyChanged。然后,您将ListView的ItemsSource属性绑定到此视图模型属性。 – Clemens

相关问题