在windows phone開發8.1:數據綁定中,我們了解了數據綁定的基本知識.今后幾篇文章會繼續深入了解數據綁定.今天我們來看在數據綁定中十分重要的INotifyPropertyChanged接口的實現.
何時實現INotifyPropertyChanged接口
官方解釋:INotifyPropertyChanged 接口用於向客戶端(通常是執行綁定的客戶端)發出某一屬性值已更改的通知。官方解釋的很模糊,估計是個人看了都不知道到底什么時候需要實現INotifyPropertyChanged接口.小夢通過實際測試給出明確結論:
首先:OneTime模式:毫無意義,因為它的綁定只有初始時候綁定一次,根本談不上改變!自然也就談不上實現INotifyPropertyChanged接口.
然后是OneWay模式:我們知道OneWay模式的含義是:綁定源的每一次變化都會通知綁定目標,但是綁定目標的改變不會改變綁定源.當綁定源的數據實體類沒有實現INotifyPropertyChanged接口時,當我們改變了數據源,我們會發現綁定目標的UI上的相應的數據不會立即變化.所以這時候就需要我們來實現INotifyPropertyChanged接口.
最后是TwoWay模式:在TwoWay模式下,當綁定源的數據實體類沒有實現INotifyPropertyChanged接口時,我們發現.控件的更改會讓數據源立即發改變,但是改變數據源,綁定目標控件卻不會立即發生改變!所以當我們需要數據源改變時相對應的UI立即改變時,就需要實現INotifyPropertyChanged接口.
總之:就是當數據源改變並需要UI立即改變時我們需要實現INotifyPropertyChanged接口.
我們可以通過這個示例來明確的體會這一點:
<StackPanel> <TextBox Header="編號" Text="{Binding ID,Mode=OneTime}" Name="tbxID" ></TextBox> <TextBox Header="書名" Text="{Binding Title,Mode=OneWay}" Name="tbxTitle" ></TextBox> <TextBox Header="價格" Text="{Binding Price,Mode=TwoWay}" Name="tbxPrice" ></TextBox> <Button Content="通過數據源修改控件的值" Click="Button_Click"></Button> <Button Content="直接修改控件的值" Click="Button_Click_1" /> <Button Content="通過控件修改數據源的值" Click="Button_Click_2" /> </StackPanel>
后台代碼:
namespace INotifyPropertyChangedDEMO { /// <summary> /// 可用於自身或導航至 Frame 內部的空白頁。 /// </summary> public sealed partial class MainPage : Page { Book book = new Book(); public MainPage() { this.InitializeComponent(); this.NavigationCacheMode = NavigationCacheMode.Required; book.ID = 0; book.Title = "ASP.NET 開發手冊"; book.Price = 40; st.DataContext = book; } private void Button_Click(object sender, RoutedEventArgs e)//通過修改數據源修改控件的值 { book.ID = 100; book.Price = 50; book.Title = "SL開發手冊"; } private async void Button_Click_1(object sender, RoutedEventArgs e)//顯示數據源的值 { await new MessageDialog(book.ID.ToString() + " " + book.Title.ToString() + " " + book.Price.ToString()).ShowAsync(); } public class Book : INotifyPropertyChanged //INotifyPropertChanged 接口定義了一個當屬性值更改時執行的事件,事件名稱為PropertyChanged。 //這個是在繼承這個接口的類必須要實現的事件 { private int _id; public int ID { get { return _id; } set { _id = value; //NotifyPropertyChange("ID"); } } private string _title; public string Title { get { return _title; } set { _title = value; //NotifyPropertyChange("Title"); } } private double _price; public double Price { get { return _price; } set { _price = value; //NotifyPropertyChange("Price"); } } public event PropertyChangedEventHandler PropertyChanged; //PropertyChangedEventArgs類型,這個類用於傳遞更改值的屬性的名稱,實現向客戶端已經更改的屬性發送更改通知。屬性的名稱為字符串類型。 private void NotifyPropertyChange(string propertyName) { if (PropertyChanged != null) { //根據PropertyChanged事件的委托類,實現PropertyChanged事件: PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } } } }
大家運行這個示例可以明顯體會INotifyPropertyChanged接口的作用.
如何實現INotifyPropertyChanged接口
上面示例的INotifyPropertyChanged接口的實現方式是最常見和最普遍的.
我們可以利用CallerMemberNameAttribute特性來簡化一下,這個特性可以根據調用方來決定傳入哪個屬性的名字.:
protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { var eventHandler = this.PropertyChanged; if (eventHandler != null) eventHandler(this, new PropertyChangedEventArgs(propertyName)); }
這樣我們在調用時可以這樣調用:
NotifyPropertyChange("ID") 改為:OnPropertyChanged();
INotifyPropertyChanged接口的最佳實現方式:
這個所謂的最佳實現方式 是channel 9的視頻中說的,實現方式如下:
public class ModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null) { if (object.Equals(storage, value)) return false; storage = value; this.OnPropertyChanged(propertyName); return true; } protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { var eventHandler = this.PropertyChanged; if (eventHandler != null) eventHandler(this, new PropertyChangedEventArgs(propertyName)); } }
相應的調用方式進一步簡化:
private string name; public string Name { get { return name; } set { this.SetProperty(ref this.name, value); } }
該睡了,明天繼續!