43

私は非常に単純です(私は願っています:))問題:

MVVM では、View は通常、ViewModel のプロパティの変更をリッスンします。ただし、たとえば、VM シグナルが発生したときに View がアニメーションを開始したり、ウィンドウを閉じたりできるように、イベントをリッスンしたい場合があります。

NotifyPropertyChanged を使用して bool プロパティを介して実行する (および false から true に変更された場合にのみアニメーションを開始する) ことは可能ですが、ハックのように感じます。意味的に正しいので、イベントを公開することをお勧めします。

また、分離コードでコードなしで実行したいと思います。これを行うとviewModel.myEvent += handler、View を GC できるようにするために手動でイベントの登録を解除する必要があるためです。 '、そして私は View で宣言的にのみプログラミングすることを好みます。

1 つの View に対して複数の ViewModel を切り替える必要があるため (毎回 View を作成すると CPU 時間がかかりすぎるため)、標準の強力なイベント サブスクリプションも良くありません。

アイデアをありがとうございます (標準的な解決策がある場合は、msdn へのリンクで十分です)。

4

5 に答える 5

3

いくつかのコメント:

  • 弱いイベント パターンを使用して、ビュー モデルのイベントにアタッチされている場合でも、ビューを確実に GC できるようにすることができます。
  • 1 つのビューに対して複数の VM を既に切り替えている場合、それはハンドラーをアタッチ/デタッチするのに理想的な場所ではないでしょうか?
  • 正確なシナリオに応じて、ビューがアニメーション、トランジション、およびその他の視覚的変化のトリガーとして使用する状態プロパティを VM に公開させることができます。Visual State Managerは、この種の作業に最適です。
于 2009-12-12T20:09:32.780 に答える
2

これは私も苦労したことです...

他の人が言っていることと似ていますが、ここにいくつかのコード スニペットの例があります... 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 を呼び出します。

ビューモデル (パブ):

 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 または特定されたものを渡すこともできます。これは、Pub で設定し、sub でチェックして、pub/sub が同期していることを確認できます。

于 2012-04-11T15:44:19.710 に答える
1

より一般的な質問としては、「なぜ ViewModel でこのイベントを処理しようとしているのですか?」というものがあります。

答えがアニメーションなどのビューのみのものと関係がある場合、ViewModel はそれについて知る必要はないと主張します: コード ビハインド (適切な場合)、Data/Event/PropertyTriggers、および新しい VisualStateManager コンストラクトは、はるかに優れたサービスを提供します。 、View と ViewModel の間の明確な分離を維持します。

イベントの結果として何かを「発生」させる必要がある場合、実際に使用したいのはコマンド パターンです。CommandManger を使用して、コード ビハインドでイベントを処理し、ビュー モデルでコマンドを呼び出します。 System.Interactivity ライブラリに添付されたビヘイビア。

いずれにせよ、ViewModel をできる限り「純粋」に保ちたいと考えています。そこに View 固有のものが表示されている場合は、おそらく間違っています。:)

于 2009-12-21T19:32:45.910 に答える
1

imho yYand セパレート

  1. 状態 - ビュー間でデータを前後に移動できるようにする <-> vm
  2. アクション - ビューモデル関数/コマンドを呼び出すことができる
  3. 通知 - 何かが起こったことをビューに知らせることができ、要素を光らせる、スタイルを切り替える、レイアウトを変更する、別の要素にフォーカスするなどのビューのアクションを実行させたい.

プロパティバインディングでこれを行うことができるのは事実ですが、トーマスが述べたように、それはハックのようなものです。はいつも私にこのように感じました。

ビューモデル別名通知から「イベント」をリッスンできるようにする私の解決策は、データコンテキストの変更を単純にリッスンすることです。変更された場合、タイプが探しているvmであることを確認し、イベントを接続します。粗雑だが単純。

私が本当に望んでいるのは、いくつかの「ビューモデルイベント」トリガーを定義し、xaml 内のすべてのもののビュー側で反応し、そうでないものの背後にあるコードにのみドロップするハンドラーを提供する簡単な方法です。 xamlで実行可能

于 2011-09-14T10:37:51.563 に答える
0

adrianm が言ったように、bool プロパティからアニメーションをトリガーすると、実際にはイベントに応答しています。具体的にはPropertyChanged、WPF サブシステムのイベントです。これは、メモリをリークしないように、正しくアタッチ/デタッチするように設計されています (イベントを自分で配線するときにこれを忘れて、そうでなければ GC する必要があるオブジェクトへの参照をアクティブにすることでメモリ リークを引き起こす可能性があります)。 .

これにより、ViewModel をDataContextコントロールとして公開し、データ バインディングを通じてデータ コンテキストのプロパティの変更に正しく応答できます。

MVVM は、WPF が提供するこれらすべての機能により、WPF で特にうまく機能するパターンであり、プロパティの変更をトリガーすることは、実際には WPF サブシステム全体を使用して目標を達成するエレガントな方法です:)

于 2009-12-21T02:22:06.553 に答える