在源对象上调用PropertyChanged(null)时多次调用IWeakEventListener.ReceiveWeakEvent()

时间:2015-10-25 23:30:30

标签: wpf mvvm-light reactive-programming weakeventmanager

我在代码中使用PropertyObserver类,以避免在PropertyChanged事件处理中进行字符串比较,并将nullstring.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();

1 个答案:

答案 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();

每个具有非空第三个参数(属性名称)的已注册侦听器将仅响应指定的属性名称​​和 nullstring.Empty。这就是为什么在原始代码上调用foreach两次的原因。