私は非常に単純な(私は願っています:))問題:
MVVMでは、Viewは通常、ViewModelのプロパティの変更をリッスンします。ただし、イベントをリッスンして、たとえばVMシグナルのときにViewがアニメーションを開始したり、ウィンドウを閉じたりできるようにしたい場合があります。
NotifyPropertyChangedでboolプロパティを介して(そしてfalseからtrueに変化したときにのみアニメーションを開始して)実行することは可能ですが、ハッキングのように感じられます。
また、コードビハインドのコードなしでそれを実行したいのですが、viewModel.myEvent += handler
を実行すると、ビューをGCできるようにイベントを手動で登録解除することになります-WPFビューはすでにプロパティを「弱く」リッスンするので、Viewで宣言的にのみプログラミングすることをお勧めします。
1つのビューに対して複数のViewModelを切り替える必要があるため、標準の強力なイベントサブスクリプションも不適切です(毎回ビューを作成するとCPU時間がかかりすぎるため)。
アイデアをありがとう(標準的な解決策があれば、msdnへのリンクで十分です)!
いくつかのコメント:
このスレッドはかなり古いですが、最近同様に取り組んだものなので$ 0.02を提供します...
他の人が言っているのと似ていますが、ここにいくつかのコードスニペットの例があります...この例は、pub/subを使用して、VM-この場合、GridViewを実行します。gvがVMと同期していることを確認するために再バインドします...
ビュー(サブ):
using Microsoft.Practices.Composite.Events;
using Microsoft.Practices.Composite.Presentation.Events;
private SubscriptionToken getRequiresRebindToken = null;
private void SubscribeToRequiresRebindEvents()
{
this.getRequiresRebindToken =
EventBus.Current.GetEvent<RequiresRebindEvent>()
.Subscribe(this.OnRequiresRebindEventReceived,
ThreadOption.PublisherThread, false,
MemoryLeakHelper.DummyPredicate);
}
public void OnRequiresRebindEventReceived(RequiresRebindEventPayload payload)
{
if (payload != null)
{
if (payload.RequiresRebind)
{
using (this.gridView.DeferRefresh())
{
this.gridView.Rebind();
}
}
}
}
private void UnsubscribeFromRequiresRebindEvents()
{
if (this.getRequiresRebindToken != null)
{
EventBus.Current.GetEvent<RequiresRebindEvent>()
.Unsubscribe(this.getRequiresRebindToken);
this.getRequiresRebindToken = null;
}
}
メモリリークを防ぐために、closeメソッドからunsubを呼び出します。
ViewModel(Pub):
private void PublishRequiresRebindEvent()
{
var payload = new RequiresRebindEventPayload();
payload.SetRequiresRebind();
EventBus.Current.GetEvent<RequiresRebindEvent>().Publish(payload);
}
ペイロードクラス
using System;
using Microsoft.Practices.Composite.Presentation.Events;
public class RequiresRebindEvent
: CompositePresentationEvent<RequiresRebindEventPayload>
{
}
public class RequiresRebindEventPayload
{
public RequiresRebindEventPayload()
{
this.RequiresRebind = false;
}
public bool RequiresRebind { get; private set; }
public void SetRequiresRebind()
{
this.RequiresRebind = true;
}
}
GUIDを渡すようにコンストラクターを設定することもできます。または、Guidで識別されるものをPubで設定し、subでチェックして、pub/subが同期していることを確認できます。
imho yYand分離
プロパティバインディングを使用してこれを実行できることは事実ですが、tomasが述べたようにハックのようなものです。いつもこんな感じでした。
ビューモデル(通知)から 'イベント'をリッスンできるようにするための私のソリューションは、データコンテキストの変更をリッスンし、それが変更されたときに、タイプが確認しているvmであることを確認し、イベントを接続します。粗雑ですがシンプルです。
私が本当に望んでいるのは、いくつかの「ビューモデルイベント」トリガーを定義し、xamlのすべてのビュー側で反応し、そうでないものについてはコードビハインドにドロップするだけのハンドラーを提供する簡単な方法です。 xamlで実行可能
より一般的な質問は、「なぜViewModelでこのイベントを処理しようとしているのですか?」です。
答えがアニメーションなどの表示のみのものと関係がある場合、ViewModelはそれについて知る必要がないと主張します:コードビハインド(適切な場合)、Data/Event/PropertyTriggers、および新しいVisualStateManager構成はより良いサービスを提供しますと、ViewとViewModelの間の明確な分離を維持します。
イベントの結果として何かが「発生」する必要がある場合、実際に使用したいのはコマンドパターンです。CommandMangerを使用するか、コードビハインドでイベントを処理し、ビューモデルでコマンドを呼び出すか、またはSystem.Interactivityライブラリに添付された動作。
どちらの方法でも、できるだけViewModelを "純粋"に保つ必要があります。そこにView固有の何かが表示される場合は、おそらく間違っています。 :)
アドリアンが言ったように、boolプロパティからアニメーションをトリガーするとき、実際にはイベントに応答しています。具体的には、WPFサブシステムが行うイベントPropertyChanged
です。これは、メモリをリークしないように正しくアタッチ/デタッチするように設計されています(イベントを自分で配線するときにこれを忘れて、GCする必要があるオブジェクトへの参照をアクティブにすることでメモリリークを引き起こす可能性があります)。 。
これにより、コントロールのDataContext
としてViewModelを公開し、データバインディングを通じてデータコンテキストのプロパティの変更に正しく応答することができます。
MVVMは、WPFがこれらすべてを提供するため、WPFで特にうまく機能するパターンであり、プロパティの変更をトリガーすることは、実際にはWPFサブシステム全体を使用して目標を達成するための洗練された方法です。