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/

