1

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

1 回答 1

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 的原因。

于 2015-11-07T10:29:10.163 回答