我在代码中使用PropertyObserver类,以避免在PropertyChanged
事件处理中进行字符串比较,并将null
或string.Empty
的处理视为其参数(其中indicates表示对象的所有属性都已更改。
此类使用PropertyChangedEventManager
在目标对象中注册回调,并实现IWeakEventListener
以在源对象上每次调用PropertyChanged
事件时进行响应。
但是在创建单元测试期间,我发现IWeakEventListener.ReceiveWeakEvent()
被称为N次,其中N是已注册的回调数。这仅在指定null或string.Empty时发生,而不是在PropertyChanged事件中给出有效属性名称时。
有谁知道为什么会发生这种情况以及如何解决这个问题?我的目标是在给出null时执行一次注册处理程序,因此我可以通过获取源对象的所有属性来更新我的目标对象。但是当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();
答案 0 :(得分:1)
好的,之前我没有理解AddListener()
方法。我只需要注册一次监听器:
PropertyChangedEventManager.AddListener(vm, obs, string.Empty);
收听源对象的所有 PropertyChanged事件。这样做将产生PropertyObserver类的正确工作:
vm.Prop1 = 1; // "Invoke handler for property Prop1"
vm.Prop2 = 2; // "Invoke handler for property Prop2"
// Now results in one console line "Foreach registered handlers and invoke one by one"
vm.RaisePropertyChanged();
每个具有非空第三个参数(属性名称)的已注册侦听器将仅响应指定的属性名称和 null
或string.Empty
。这就是为什么在原始代码上调用foreach两次的原因。