C#優(yōu)雅的實(shí)現(xiàn)INotifyPropertyChanged接口
INotifyPropertyChanged接口在WPF或WinFrom程序中使用還是經(jīng)常用到,常用于通知界面屬性變更。標(biāo)準(zhǔn)寫法如下:
class NotifyObject : INotifyPropertyChanged
{
private int number;
public int Number
{
get { return number; }
set { number = value; OnPropertyChanged("Number"); }
}
private string text;
public string Text
{
get { return text; }
set { text = value; OnPropertyChanged("Text"); }
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName = "")
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}這種寫法的兩個(gè)問題是
- 對屬性名使用了字符串硬編碼,容易寫錯(cuò),也不方便重構(gòu)
- 冗余代碼,如果屬性較多的時(shí)候?qū)懙孟胪?/li>
我在博客文章使用CallerMemberName簡化InotifyPropertyChanged的實(shí)現(xiàn)中介紹了通過Caller Information解決屬性名稱字符串硬編碼的問題。但是仍然不能解決冗余代碼的問題。對于第二個(gè)問題,往往是通過AOP的方式實(shí)現(xiàn),一般的實(shí)現(xiàn)方式有兩種:
- 通過代理對象封裝
- 通過編譯期間代碼注入的方式實(shí)現(xiàn)
我增在項(xiàng)目中使用過DynamicObject封裝來實(shí)現(xiàn)過,主要原理是用實(shí)現(xiàn)一個(gè)PocoNotifyWrapper的DynamicObject類,托管其屬性的讀寫動(dòng)作,并附加IntofyPropertyChanged接口實(shí)現(xiàn)。
這種方式是動(dòng)態(tài)的AOP了,是一個(gè)通用的方式,并且擴(kuò)展性比較器,可以通過繼承PocoNotifyWrapper來實(shí)現(xiàn)多態(tài)。用它做ViewMode層還是比較方便。
不過一個(gè)不大好的地方是DynamicObject是丟失了屬性類型信息的,有時(shí)綁定時(shí)會(huì)出錯(cuò)(如將一個(gè)TextBox的Text綁定到一個(gè)封裝后的Int類型對象時(shí)會(huì)不進(jìn)行自動(dòng)類型轉(zhuǎn)換)。要解決它還需要實(shí)現(xiàn)一些其它的接口,實(shí)現(xiàn)起來還是有些復(fù)雜的,并且項(xiàng)目進(jìn)度比較緊張,沒有太多時(shí)間來完善它。
另外一種方式是通過編譯期間代碼注入方式來實(shí)現(xiàn):


最開始見的是PostSharp的一個(gè)實(shí)現(xiàn): http://doc.postsharp.net/inotifypropertychanged-add。不過PostSharp是收費(fèi)的,后來也逐漸由了許多其它的免費(fèi)的解決方案。本文這里介紹的是一個(gè)開源的解決方案:Fody。
使用它非常簡單,首先通過Nuget安裝庫:PM> Install-Package PropertyChanged.Fody。然后在需要實(shí)現(xiàn)屬性通知的類上加一個(gè)[ImplementPropertyChanged]即可:
[ImplementPropertyChanged]
public class Person
{
public string GivenNames { get; set; }
public string FamilyName { get; set; }
public string FullName => string.Format("{0} {1}", GivenNames, FamilyName);
}編譯后生成的代碼如下:
public class Person : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
string givenNames;
public string GivenNames
{
get { return givenNames; }
set
{
if (value != givenNames)
{
givenNames = value;
OnPropertyChanged("GivenNames");
OnPropertyChanged("FullName");
}
}
}
string familyName;
public string FamilyName
{
get { return familyName; }
set
{
if (value != familyName)
{
familyName = value;
OnPropertyChanged("FamilyName");
OnPropertyChanged("FullName");
}
}
}
public string FullName
{
get
{
return string.Format("{0} {1}", GivenNames, FamilyName);
}
}
public virtual void OnPropertyChanged(string propertyName)
{
var propertyChanged = PropertyChanged;
if (propertyChanged != null)
{
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}基本上對代碼沒有注入,不需要安裝插件,也不影響調(diào)試,實(shí)現(xiàn)非常簡單,非常方便。
需要注意的是,如果實(shí)現(xiàn)了INotifyPropertyChanged接口,即使沒有[ImplementPropertyChanged]標(biāo)記,默認(rèn)也會(huì)注入。
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請查看下面相關(guān)鏈接
相關(guān)文章
UpdateLayeredWindow實(shí)現(xiàn)任意異形窗口使用詳解
這篇文章主要為大家介紹了UpdateLayeredWindow實(shí)現(xiàn)任意異形窗口使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
C#中實(shí)現(xiàn)PriorityQueue優(yōu)先級隊(duì)列的代碼
這篇文章主要介紹了C#中PriorityQueue優(yōu)先級隊(duì)列的實(shí)現(xiàn),構(gòu)造初始化這部分主要介紹關(guān)鍵的字段和方法,比較器的初始化以及堆的初始化,需要的朋友可以參考下2021-12-12
c#斐波那契數(shù)列(Fibonacci)(遞歸,非遞歸)實(shí)現(xiàn)代碼
c#斐波那契數(shù)列(Fibonacci)(遞歸,非遞歸)實(shí)現(xiàn)代碼,需要的朋友可以參考一下2013-05-05
c#創(chuàng)建windows服務(wù)入門教程實(shí)例
windows服務(wù)是windows系統(tǒng)中一類特殊的應(yīng)用程序,一般情況下它們只會(huì)在后臺(tái)運(yùn)行,不會(huì)影響前臺(tái)操作,非常適合做一些不需要用戶參與的而又需要長時(shí)間執(zhí)行的任務(wù)2014-04-04
Unity?UGUI的CanvasScaler畫布縮放器組件介紹使用
這篇文章主要為大家介紹了Unity?UGUI的CanvasScaler畫布縮放器組件介紹使用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07

