msdn中 ObservableCollection<T> 類 表示一個動態數據集合,在添加項、移除項或刷新整個列表時,此集合將提供通知。
在許多情況下,所使用的數據是對象的集合。 例如,數據綁定中的一個常見方案是使用 ItemsControl(如 ListBox、ListView 或 TreeView)來顯示記錄的集合。
可以枚舉實現 IEnumerable 接口的任何集合。 但是,若要設置動態綁定,以便集合中的插入或刪除操作可以自動更新 UI,則該集合必須實現 INotifyCollectionChanged 接口。 此接口公開 CollectionChanged 事件,只要基礎集合發生更改,都應該引發該事件。
WPF 提供 ObservableCollection<T> 類,它是實現 INotifyCollectionChanged 接口的數據集合的內置實現。
還有許多情況,我們所使用的數據只是單純的字段或者屬性,此時我們需要為這些字段或屬性實現INotifyPropertyChanged接口,實現了該接口,只要字段或屬性的發生了改變,就會提供通知機制。
ObservableCollection<T>實現
前台xmal
<Window x:Class="WpfApplication1.WindowObservable" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window8" Height="356" Width="471"> <Grid> <StackPanel Height="295" HorizontalAlignment="Left" Margin="10,10,0,0" Name="stackPanel1" VerticalAlignment="Top" Width="427"> <TextBlock Height="23" Name="textBlock1" Text="學員編號:" /> <TextBox Height="23" Name="txtStudentId" Width="301" HorizontalAlignment="Left"/> <TextBlock Height="23" Name="textBlock2" Text="學員列表:" /> <ListBox Height="156" Name="lbStudent" Width="305" HorizontalAlignment="Left"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Name="stackPanel2" Orientation="Horizontal"> <TextBlock Text="{Binding Id,Mode=TwoWay}" Margin="5" Background="Beige"/> <TextBlock Text="{Binding Name,Mode=TwoWay}" Margin="5"/> <TextBlock Text="{Binding Age,Mode=TwoWay}" Margin="5"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> <Button Content="Button" Height="23" Name="button1" Width="75" HorizontalAlignment="Left" Click="button1_Click" /> </StackPanel> </Grid> </Window>
后台cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; using System.Collections.ObjectModel; using System.ComponentModel; namespace WpfApplication1 { public partial class WindowObservable : Window { ObservableCollection<Students> infos = new ObservableCollection<Students>() { new Students(){ Id=1, Age=11, Name="Tom"}, new Students(){ Id=2, Age=12, Name="Darren"}, new Students(){ Id=3, Age=13, Name="Jacky"}, new Students(){ Id=4, Age=14, Name="Andy"} }; public WindowObservable() { InitializeComponent(); this.lbStudent.ItemsSource = infos; this.txtStudentId.SetBinding(TextBox.TextProperty, new Binding("SelectedItem.Id") { Source = lbStudent }); } private void button1_Click(object sender, RoutedEventArgs e) { infos[1] = new Students() { Id = 4, Age = 14, Name = "這是一個集合改變" }; infos[2].Name = "這是一個屬性改變"; } public class Students { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } } } }
在這個例子中我們將Students數據對象用ObservableCollection<T>來修飾。這樣當我們點擊click的時候我們看到。當我們點擊后只有student整個對象的改變引發了后台通知機制。
INotifyPropertyChanged實現
INotifyPropertyChanged會向客戶端發出某一屬性值已更改的通知。當元素屬性值改變時,會通知后台model
前台代碼不變,我們讓后台Students Model實現INotifyPropertyChanged接口。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; using System.Collections.ObjectModel; using System.ComponentModel; namespace WpfApplication1 { public partial class WindowObservable : Window { ObservableCollection<Students> infos = new ObservableCollection<Students>() { new Students(){ Id=1, Age=11, Name="Tom"}, new Students(){ Id=2, Age=12, Name="Darren"}, new Students(){ Id=3, Age=13, Name="Jacky"}, new Students(){ Id=4, Age=14, Name="Andy"} }; public WindowObservable() { InitializeComponent(); this.lbStudent.ItemsSource = infos; this.txtStudentId.SetBinding(TextBox.TextProperty, new Binding("SelectedItem.Id") { Source = lbStudent }); } private void button1_Click(object sender, RoutedEventArgs e) { infos[1] = new Students() { Id = 4, Age = 14, Name = "這是一個集合改變" }; infos[2].Name = "這是一個屬性改變"; } public class Students : INotifyPropertyChanged { string _name; public int Id { get; set; } public string Name { get { return _name; } set { _name = value; OnPropertyChanged("Name"); } } public int Age { get; set; } protected internal virtual void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } public event PropertyChangedEventHandler PropertyChanged; } } }
此時我們再 運行代碼會發現
使用DataContext為頁面對象設置上下文
不管是集合還是對象都發生了改變。至此。我們的整個后台通知就能完美監視任何對象變動。
但是現在還有一個問題。我們如果在點擊事件里面給infos賦值一個新的集合數據。如下
private void button1_Click(object sender, RoutedEventArgs e) { infos[1] = new Students() { Id = 4, Age = 14, Name = "這是一個集合改變" }; infos[2].Name = "這是一個屬性改變";
infos = new ObservableCollection<Students>() {
new Students(){ Id=1, Age=11, Name="這是改變后的集合"}, new Students(){ Id=2, Age=12, Name="這是改變后的集合"}, new Students(){ Id=3, Age=13, Name="這是改變后的集合"}, new Students(){ Id=4, Age=14, Name="這是改變后的集合"} };
}
會發現數據並沒有變更。這是為什么?我們明明實現了ObservableCollection<T>類型啊。這是因為infos這個集合的地址變更並沒有實現通知機制。當我們new一個對象賦值給infos時候,infos的地址指向變更了。所以集合里面數據的變化,infos變更后的數據就參與綁定了。我們這時候可以通過DataContext實現數據數據項的變更通知。我們添加一個ViewModel類,實現INotifyPropertyChanged接口
public class ViewModel : INotifyPropertyChanged { private ObservableCollection<Students> studentList; public ObservableCollection<Students> StudentList { get { return this.studentList; } set { if (this.studentList != value) { this.studentList = value; OnPropertyChanged("StudentList"); } } } public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = this.PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } }
windowsObservable類修改為如下
public partial class WindowObservable : Window { ViewModel viewModel = new ViewModel(); public WindowObservable() { InitializeComponent(); viewModel.StudentList = new ObservableCollection<Students>() { new Students(){ Id=1, Age=11, Name="Tom"}, new Students(){ Id=2, Age=12, Name="Darren"}, new Students(){ Id=3, Age=13, Name="Jacky"}, new Students(){ Id=4, Age=14, Name="Andy"} }; this.lbStudent.DataContext = viewModel; } private void button1_Click(object sender, RoutedEventArgs e) { viewModel.StudentList[1] = new Students() { Id = 4, Age = 14, Name = "這是一個集合改變" }; viewModel.StudentList = new ObservableCollection<Students>() { new Students(){ Id=19, Age=111, Name="這是變化后的幾何"}, new Students(){ Id=29, Age=121, Name="這是變化后的幾何"}, new Students(){ Id=39, Age=131, Name="這是變化后的幾何"}, new Students(){ Id=49, Age=141, Name="這是變化后的幾何"} }; viewModel.StudentList[2].Name = "這是一個屬性改變"; } }
我們給xaml listbox設置如下綁定
ItemsSource="{Binding StudentList, Mode=TwoWay}"
運行程序我們發現集合的改變也會被通知到前台。
代碼參考:http://blog.csdn.net/fwj380891124/article/details/8194190
本文地址:http://www.cnblogs.com/santian/p/4366832.html
博客地址:http://www.cnblogs.com/santian/