我在我的代码中使用PropertyObserver类来避免在PropertyChanged
事件处理中进行字符串比较,并将处理 null
或string.Empty
作为其参数的因素(这表明对象的所有属性都已更改)。
此类用于PropertyChangedEventManager
在目标对象中注册回调,并实现IWeakEventListener
每次PropertyChanged
在源对象上调用事件时响应。
但是在创建单元测试的过程中,我发现它IWeakEventListener.ReceiveWeakEvent()
被调用了 N 次,其中 N 是注册回调的数量。这仅在指定 null 或 string.Empty 时发生,而不是在 PropertyChanged 事件中给出有效属性名称时发生。
有谁知道为什么会发生这种情况以及如何解决?我的目标是在给出 null 时对已注册的处理程序进行一次 foreach,这样我就可以通过获取源对象的所有属性来更新我的目标对象。但是当ReceiveWeakEvent()
被调用 N 次时,foreach 将被重复 N 次!
为了说明这一点,下面是 PropertyObserver 类和源类的简化版本(我使用 MVVM Light 的ObservableObject
实现INotifyPropertyChanged
):
public class PropertyObserver : IWeakEventListener {
public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) {
if (managerType == typeof(PropertyChangedEventManager)) {
string propertyName = ((PropertyChangedEventArgs)e).PropertyName;
if (string.IsNullOrEmpty(propertyName)) {
Console.WriteLine ("Foreach registered handlers and invoke one by one");
} else {
Console.WriteLine ("Invoke handler for property {0}", propertyName);
}
return true;
}
return false;
}
}
public class ViewModel : ObservableObject {
private int mProp1;
private int mProp2;
public int Prop1 {
get { return mProp1; }
set {
mProp1 = value;
RaisePropertyChanged("Prop1");
}
}
public int Prop2 {
get { return mProp2; }
set {
mProp2 = value;
RaisePropertyChanged("Prop2");
}
}
public void RaiseAllPropertyChanged() {
RaisePropertyChanged(null);
}
}
在控制台应用程序的 Main 中,我们可以这样称呼它们:
var vm = new ViewModel();
var obs = new PropertyObserver();
// Normally this is done inside the PropertyObserver class.
PropertyChangedEventManager.AddListener(vm, obs, "Prop1");
PropertyChangedEventManager.AddListener(vm, obs, "Prop2");
vm.Prop1 = 1; // Results in a console line "Invoke handler for property Prop1"
vm.Prop2 = 2; // Results in a console line "Invoke handler for property Prop2"
// Results in two console lines: "Foreach registered handlers and invoke one by one", expected is only 1!
vm.RaiseAllPropertyChanged();