正如答案所示,我必須實現我自己的解決方案。對於其他人的利益,我在這裏提出的是:
的擴展PropertyChanged事件
此活動已專門設計的,與舊的PropertyChanged事件的向後兼容。它可以與調用者的簡單PropertyChangedEventArgs交替使用。當然,在這種情況下,事件處理程序負責檢查傳遞的PropertyChangedEventArgs是否可以向下轉換爲PropertyChangedExtendedEventArgs,如果他們想使用它。如果所有他們感興趣的都是PropertyName屬性,則不需要向下轉換。
public class PropertyChangedExtendedEventArgs<T> : PropertyChangedEventArgs
{
public virtual T OldValue { get; private set; }
public virtual T NewValue { get; private set; }
public PropertyChangedExtendedEventArgs(string propertyName, T oldValue, T newValue)
: base(propertyName)
{
OldValue = oldValue;
NewValue = newValue;
}
}
的擴展的PropertyChanged接口
如果程序員希望創建一個事件力通知特性,包括一箇舊值和一個新的價值,他們只需要實現以下接口:
// Summary: Notifies clients that a property value is changing, but includes extended event infomation
/* The following NotifyPropertyChanged Interface is employed when you wish to enforce the inclusion of old and
* new values. (Users must provide PropertyChangedExtendedEventArgs, PropertyChangedEventArgs are disallowed.) */
public interface INotifyPropertyChangedExtended<T>
{
event PropertyChangedExtendedEventHandler<T> PropertyChanged;
}
public delegate void PropertyChangedExtendedEventHandler<T>(object sender, PropertyChangedExtendedEventArgs<T> e);
例1
用戶現在可以指定一個更先進的NotifyPropertyChanged
方法,允許屬性setter到他們原來的值傳遞:
public String testString
{
get { return testString; }
set
{
String temp = testString;
testValue2 = value;
NotifyPropertyChanged("TestString", temp, value);
}
}
您的新NotifyPropertyChanged
方法是這樣的:
protected void NotifyPropertyChanged<T>(string propertyName, T oldvalue, T newvalue)
{
OnPropertyChanged(this, new PropertyChangedExtendedEventArgs<T>(propertyName, oldvalue, newvalue));
}
和OnPropertyChanged
與往常一樣:
public virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(sender, e);
}
例2
或者,如果你喜歡使用lambda表達式,並用硬編碼的屬性名稱字符串做掉完全,您可以使用以下命令:
public String TestString
{
get { return testString; }
private set { SetNotifyingProperty(() => TestString, ref testString, value); }
}
這是由以下魔法支持:
protected void SetNotifyingProperty<T>(Expression<Func<T>> expression, ref T field, T value)
{
if (field == null || !field.Equals(value))
{
T oldValue = field;
field = value;
OnPropertyChanged(this, new PropertyChangedExtendedEventArgs<T>(GetPropertyName(expression), oldValue, value));
}
}
protected string GetPropertyName<T>(Expression<Func<T>> expression)
{
MemberExpression memberExpression = (MemberExpression)expression.Body;
return memberExpression.Member.Name;
}
性能
如果關注性能,請參閱此問題:Implementing NotifyPropertyChanged without magic strings。
總之,開銷很小。添加舊值並切換到擴展事件大約有15%的減速,仍然允許每秒一百萬次的屬性通知,並且切換到lambda表達式是一個5倍的放緩,允許大約10萬次屬性通知第二。這些數字遠遠無法在任何UI驅動的應用程序中形成瓶頸。
我的microbench標記被證明能夠產生類似的結果,但是根據每個通知產生多少垃圾,我發現過度使用表達式調用INPC會給GC帶來額外的壓力,並最終導致更多的Gen1集合。儘管設計並不好(還有很多其他的東西可以改進),但改回字符串使我們在一個特定的WPF應用程序中獲得了明顯的性能提升。 –
我試圖使用此代碼,並有ViewModel實現接口'INotifyPropertyChangedExtended'而不是通常的'INotifyPropertyChanged',但我沒有得到雙向綁定。 –
xavigonza
雙向綁定適用於我。可能有些東西你錯過了... 但是請記住,你不需要實現INotifyPropertyChangedExtended接口。在你的類中,你仍然可以實現INotifyPropertyChanged,所以你的類定義不會改變...我發現INotifyPropertyChangedExtended 雖然有點混亂。要點是,不要實現該接口,只需使用PropertyChangedExtendedEventArgs。 –
lightxx