要自動更新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中,因爲ObservableCollection列表對象不是新的列表對象,而是現有列表對象(已連接到listView.ItemsSource),並且它在Device.StarTimer()的回調中使用新的DateTime條目進行了擴展。 , 真的嗎? –
對於示例2還有一件事,如果我不想在後臺代碼中將對象的集合明確分配給listView.ItemsSource,那麼我可以在後端使用ViewModel(其一些公共屬性字段作爲對象的集合),並且那麼我怎樣才能在Xaml文件中將ViewModel綁定到listView的ItemsSource? –
你的第一個評論:是的,這是真的(並已在答案中解釋)。對於第二種:您將擁有一個視圖模型類,其中包含實現INotifyPropertyChanged接口的Items屬性(類型爲ObservableCollection),並在Items屬性更改時觸發PropertyChanged,即設置爲新集合實例時觸發PropertyChanged。然後,您將ListView的ItemsSource屬性綁定到此視圖模型屬性。 –
Clemens