1

コードでPropertyObserverクラスを使用して、PropertyChangedイベント処理での 文字列比較を回避し、nullまたはstring.Emptyその引数としての処理を除外しています (これ、オブジェクトのすべてのプロパティが変更されたことを示します)。

このクラスはPropertyChangedEventManager、ターゲット オブジェクトにコールバックを登録するために使用し、ソース オブジェクトでイベントが呼び出されるIWeakEventListenerたびに応答するように実装します。PropertyChanged

しかし、単体テストの作成中にIWeakEventListener.ReceiveWeakEvent()、登録されたコールバックの数として N を使用して、 が N 回呼び出されることがわかりました。これは、PropertyChanged イベントで有効なプロパティ名が指定された場合ではなく、null または string.Empty が指定された場合にのみ発生します。

なぜこれが起こっているのか、それを修正する方法を知っている人はいますか? 私の目標は、null が指定されたときに登録済みハンドラーの foreach を 1 回実行することです。これにより、ソース オブジェクトのすべてのプロパティを取得してターゲット オブジェクトを更新できます。しかし、ReceiveWeakEvent()が N 回呼び出されると、foreach は N 回繰り返されます!

それを説明するために、以下は PropertyObserver クラスとソース クラスの簡略化されたバージョンです (実装には MVVM Light を使用しています) ObservableObjectINotifyPropertyChanged

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()前に方法を理解していませんでした。リスナーを登録する必要があるのは 1 回だけです。

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

空でない 3 番目の引数 (プロパティ名) を持つ登録済みの各リスナーは、指定されたプロパティ名および nullまたはのみに応答しますstring.Empty。これが、元のコードで foreach が 2 回呼び出された理由です。

于 2015-11-07T10:29:10.163 に答える