3

少し調べてみましたが、もっと簡単な答えが見つからないことに驚いています。私は単純な MVVM モデルに従っており、パブリック プロパティ (get/set) によって公開されるフィールドとして別のビュー モデル (「childVM」) を保持するビュー モデル (「parentVM」) を持っています。私が抱えている問題は、親の初期化子で子ビュー モデルの propertychanged イベントをサブスクライブしようとしていることです。ただし、新しい childVM が設定されると、イベント ハンドラは失われます。

public parentVM : INotitifyPropertyChange{
    private _childVM = new childVM();

    public parentVM(){
        _childVM.PropertyChanged += someHandler;
    }


    public childVM {
         get{
             return _childVM;
         }
         set{
             _childVM = value;
             //EVENTHANDLERS ARE NOW GONE
         }
    }
    ....
}

既存のイベント ハンドラーを新しいオブジェクトに転送する方法はありますか?

これは簡単な例です。私は単純に行を移動できることを知っています:

_childVM.PropertyChange += someHandler;

ただし、これはイベントをサブスクライブする外部オブジェクトでは機能しません。そのような場合、オブジェクトが何であり、ハンドラーが何であるかを知ることはまずありません。

おそらく、+= eventHandler からより手動の AddHander メソッドに内部的に変更する List を参照することによる回避策があり、将来の参照のために List にデータが入力されます。この時点でアウトロードを考えているだけです。

PS 例に構文エラーがある場合は、ご容赦ください。私はインテリセンスを持っておらず、これは実際のコードではありません...要点を伝えようとしているだけです。

4

3 に答える 3

2

の新しいインスタンスをまったく作成せずchildVM、単に内部モデルを更新することを検討します。

ただし、これを望まない場合は、以下のコードで説明したことを実行する必要があります。元のイベント ハンドラーも削除されていることに注意してくださいChildVM(コードでは、より標準的な大文字を使用しました)。イベント ハンドラーを削除しないと、多くの場合、メモリ リークが発生します。

class ParentVM
{
    private ChildVM _childVM = new ChildVM();

    public ParentVM()
    {
        _childVM.PropertyChanged += SomeHandler;
    }

    public ChildVM ChildVM
    {
        get
        {
            return _childVM;
        }
        set
        {
            foreach (var handler in _childVM.GetPropertyChangedHandlers())
            {
                _childVM.PropertyChanged -= handler;
                value.PropertyChanged += handler;
            }

            _childVM = value;
        }
    }

    private void SomeHandler(object sender, PropertyChangedEventArgs e)
    {
    }
}

残念ながら、イベントを定義する型の外部からGetPropertyChangedHandlers呼び出すことはできないため、子ビュー モデル クラスでこの追加のメソッドが必要になります。GetInvocationListのコードは次のChildVMとおりです。

class ChildVM : INotifyPropertyChanged
{
    public PropertyChangedEventHandler[] GetPropertyChangedHandlers()
    {
        return PropertyChanged.GetInvocationList().
               OfType<PropertyChangedEventHandler>().ToArray();
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

別の解決策に戻る: これらのイベントにサブスクライブする外部コードを説明する必要がありますか? 単純なデータ バインディングを行っている場合PropertyChangedは、プロパティが設定されたときにイベントを発生させるだけChildVMで、このような余分なコードを一切使わずに問題を処理できます。

于 2013-04-02T17:46:50.267 に答える
2

EventAggregator への移行を検討しましたか?

たとえば Prism や caliburn.micro など、周りにはたくさんあります。

基本的な考え方は次のとおりです。イベントを発行するエンティティと、イベントをサブスクライブする (つまり、イベントを処理する) エンティティがあります。そのため、直接サブスクライブ (+=) からより疎結合のアーキテクチャに移行します。イベントを EventAggregator にのみ発行し、それらのイベントのハンドラーを呼び出す必要がある場所 (+= の前のマルチキャスト デリゲート) を処理します。

これは非常に簡単で、コードにこの依存関係がなくなります。

以下のリンクをご覧ください。

EventAggregator の MSDN Prism の説明 (とても良い)

EventAggregator の caliburn.micro の説明

于 2013-04-02T17:55:24.660 に答える
1

より良い答え:

ParentVM に INotifyPropertyChanged を実装します。ChildVM を変更したときにイベントを発生させます。ChildVM イベントをサブスクライブする外部オブジェクトは、ParentVMs プロパティ変更イベントをサブスクライブでき、変更が通知されたときに ChildVM のイベント ハンドラーを更新できます。

元の回答: 私は2つのメソッドを作成SubscribeChildVMEvents(ChildVM)UnsubscribeChildVMEvent(ChildVM)、セッターでこれを行います:

set{
  UnsubscribeChildVMEvents(_childVM);
             _childVM = value;
  SubscribeChildVMEvents(_childVM);
             //EVENTHANDLERS ARE NOW NOT GONE
         }

オブジェクトからイベント ハンドラーを削除することをお勧めします。

于 2013-04-02T17:39:31.980 に答える