對於MVVM中Model的屬性,實在是開發中一個非常基礎的概念,在WP7時代,我們這樣寫:
public class TestModel:INotifyPropertyChanged { private string _name; public string Name { get { return _name; } set { if (_name!=value) { _name = value; OnNotifyPropertyChanged("Name"); } } } public event PropertyChangedEventHandler PropertyChanged; public void OnNotifyPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } }
這實在是在WP7時代開發人員的基本功啊。不過有沒有發現,每次都需要用字串傳遞的那個屬性名稱字,寫入程式碼,在大部分情況下,這個名字和前面的定義的屬性名稱字是一致的,再靠手寫純屬浪費(當然,很多人會偷懶一下寫個代碼產生器)。還有個重要的問題就是這個字串一旦寫錯就悲劇了,還不容易發現。前兩天看VS2012啟動頁上的一些視頻教程有一個關於單元測試的例子,就是在說這個問題,可見這確實是個問題。
在WIN8開發中,由於使用了.Net 4.5和C# 5.0,引入了一個新特性。在建立的Windows市集項目中,VS會自動產生一些代碼,其中就可以發現一些端倪,不過可能有的朋友不會在第一時間去看(包括我,也是後來很偶然才發現的),所以在這裡把這個發現分享給大家,先上代碼:
using System.Runtime.CompilerServices; public class TestModel : INotifyPropertyChanged { private string _name; public string Name { get { return _name; } set { SetProperty(ref _name, value); } } 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)); } } }
同樣的一個Name屬性,用新寫法之後,完成之前的功能就只需要一句話,非常簡潔,而且沒有寫入程式碼。再也不用苦哈哈的手寫那麼複雜重複的Property屬性了~
簡單說明一下,要引入System.Runtime.CompilerServices命名空間,因為SetProperty<T>需要接收的參數中的最後一項為propertyName,而這個Name我們卻不想通過手工編碼傳遞,系統提供了一個傳遞調用者名字的方式,就如上面代碼所示,對參數加上[CallerMemberName]屬性,同時把這個參數設定預設值null(這樣就可以在調用時“忽略”掉這個參數,當然所有預設參數要放在參數列表的最後面)。在程式執行時,會自動傳遞調用者的名字,如上面是Name屬性調用,傳遞過來的就是“Name”這個字串。
錦燕雲(微博:http://weibo.com/jinyanyun )