简体   繁体   English

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

[英]IWeakEventListener.ReceiveWeakEvent() called multiple times when PropertyChanged(null) is called on source object

I'm using the PropertyObserver class in my code to avoid doing string comparisons in PropertyChanged event handling and factor out the handling of null or string.Empty as its argument (Which indicates that all properties of an object has changed). 我在代码中使用了PropertyObserver类,以避免在PropertyChanged事件处理中进行字符串比较,并排除对nullstring.Empty作为其参数的处理(这表明对象的所有属性均已更改)。

This class uses PropertyChangedEventManager to register callbacks in the target object and implements IWeakEventListener to respond every time PropertyChanged event is invoked on the source object. 此类使用PropertyChangedEventManager在目标对象中注册回调,并实现IWeakEventListener以在每次在源对象上调用PropertyChanged事件时进行响应。

But during the creation of a unit test I found out that the IWeakEventListener.ReceiveWeakEvent() is called N number of times, with N as the number of the registered callbacks. 但是在创建单元测试期间,我发现IWeakEventListener.ReceiveWeakEvent()被调用了N次,其中N为已注册的回调的数量。 This only occurs when null or string.Empty is specified, not when a valid property name is given in the PropertyChanged event. 仅在指定了null或string.Empty时才会发生,而在PropertyChanged事件中给出有效的属性名时则不会发生。

Does anyone knows why this is happening and how to fix it? 有谁知道为什么会这样以及如何解决? My goal is to do a foreach of the registered handlers ONE time when null is given, so I can update my target object by getting all the properties of the source object. 我的目标是在给定null时一次对注册处理程序进行一次foreach,因此我可以通过获取源对象的所有属性来更新目标对象。 But when ReceiveWeakEvent() is called N times then the foreach will be repeated N times! 但是,当ReceiveWeakEvent()被调用N次时,foreach将重复N次!

To illustrate it, the following is a simplified version of the PropertyObserver class and the source class (I'm using MVVM Light's ObservableObject for INotifyPropertyChanged implementation): 为了说明这一点,以下是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);
    }
}

And in a console app's Main we can call them like so: 在控制台应用程序的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();

Okay, I didn't understand the AddListener() method before. 好的,我以前不了解AddListener()方法。 I only need to register a listener once: 我只需要注册一次侦听器:

PropertyChangedEventManager.AddListener(vm, obs, string.Empty);

to listen to all PropertyChanged events of a source object. 侦听源对象的所有 PropertyChanged事件。 Doing this will produce the correct working of the PropertyObserver class: 这样做将产生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();

Each registered listener with non-empty third argument (the property name) will respond to only the specified property name and null or string.Empty . 每个具有非空第三个参数(属性名称)的注册侦听器将仅响应指定的属性名称以及 nullstring.Empty So that's why the foreach was invoked twice on the original code. 这就是为什么在原始代码上两次调用foreach的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM