web-dev-qa-db-ja.com

WPF MVVMパターンのコードビハインドを回避する理由

Model-View-ViewModelデザインパターンを使用したWPFアプリ の記事で、Josh Smithの著者は次のように述べています。

(1)適切に設計されたMVVMアーキテクチャでは、ほとんどのビューの分離コードは空にするか、せいぜいそのビューに含まれるコントロールとリソースを操作するコードのみを含める必要があります。 (2)イベントのフックやViewModel自体から呼び出すのが非常に難しいメソッドの呼び出しなど、ViewModelオブジェクトと対話するViewのコードビハインドにコードを記述する必要がある場合もあります。

私の質問は、(1)で、空のコードビハインドが適切に設計されたMVVMと見なされる理由です。(空のコードビハインドは常に良いと思われます。)

編集:私の質問は、次のように、なぜAttachedCommandBehaviorInvokeCommandActionのようなアプローチが分離コードを回避しようとするのかということです。

詳細を説明します。

(1)に関する限り、 AttachedCommandBehavior から次のような状況になると思います。 BorderはICommandSourceMouseRightButtonDownを実装しないため、一般にイベントとICommandをバインドすることはできませんが、 AttachedCommandBehavior =。

<!-- I modified some code from the AttachedCommandBehavior to show more simply -->
<Border>
    <local:CommandBehaviorCollection.Behaviors>
           <local:BehaviorBinding Event="MouseRightButtonDown" 
                  Command="{Binding SomeCommand}" 
                  CommandParameter="A Command on MouseRightButtonDown"/>
    </local:CommandBehaviorCollection.Behaviors>
</Border>

[〜#〜]または[〜#〜]

System.Windows.Interactivity.InvokeCommandActionでこれを行うことができます。

<Border xmlns:i="clr-namespace:System.Windows.Interactivity;Assembly=System.Windows.Interactivity" >
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseRightButtonDown">
            <i:InvokeCommandAction Command="{Binding SomeCommand}" 
               CommandParameter="A Command on MouseRightButtonDown"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Border>

しかし、

上記の(2)Josh SimthにリンクされているBorder_MouseRightButtonDownメソッドを持つ次のXAMLとそのコードビハインドを使用します。

<Border MouseRightButtonDown ="Border_MouseRightButtonDown"/>

上記のようにコードビハインドを使用することは、これらの違いがコマンドのバインドまたはイベントハンドラーの追加だけであるという理由だけで悪くないと思います。

これについてどう思う?

46
Jin-Wook Chung

空の分離コードが適切に設計されたMVVMと見なされる理由

コンストラクターでInitializeComponent()の呼び出しのみで構成される分離コードファイルがあるということは、純粋性が達成されたことを意味します。分離コードのロジックはまったくありません。ビューモデルまたはモデルに正しく属するコードでビューを汚染していない。これは、いくつかのことを意味します。

  • ビューモデル(およびモデル)は、単独でテストする方が簡単です
  • 良好なレベルの疎結合を達成しました。これは、メンテナンスと拡張性の観点から優れた利点があります。

UIを変更する必要がある場合、つまり、ListViewの使用からDataGridに切り替える場合、または標準のMicrosoftコントロールの使用から他のベンダーの使用に変更する場合、利点は本当に顕著になります。

ただし、前述のように、分離コードファイル内の小さなコードを避けることは不可能な場合があります。確認する必要があるのは、所有するコードが純粋にUI関連であることです。例として、ComboAとComboBがあり、ComboAでの選択に応じてComboBが設定されている場合、ビューからComboBのSelectedIndexを設定することは問題ありませんが、ComboBのItemsまたはSelectedItemを設定することはできません。関連するデータと、ビューモデルへのバインドを介して指定する必要があるデータの両方。 SelectedIndexプロパティは、視覚的に直接関連しており、実際のデータからはある程度独立しています(ビューモデルとは無関係です)。

ビューのコードビハインドからビューモデルにアクセスする場合は、インターフェイスを介して試してみてください。これは、ビューモデルがインターフェイスとしてビューに挿入または提供されることを意味します。 (バインディングサブシステムは、インターフェイスを認識または気にしないことに注意してください。通常の方法でバインドを続行します。これにより、コードが改善され、密結合が少なくなります)。私がコーディングした方法では、ビューモデルはビューが存在することを認識せず、ビューはビューモデルをインターフェースとしてしか認識しません。

ただし、MVVMはパターンであり、パターンは特定の状況で特定の結果を達成するための単純な レシピまたは処方 であることに注意してください。非信者や非従順者が何らかの煉獄に行く宗教として扱われるべきではありません(ただし、 maintenance hell の煉獄を避けたいなら、パターンへの順守は良いです)および コードの匂い )。

この特定のパターンがどのように役立つかの優れた例が必要な場合は、ASP.Netでいくつかのかなり複雑な画面を作成してから、同じものをWPFまたはSilverlightで作成して、違いに注意してください。


編集:

あなたの質問のいくつかに答えさせてください。

私のビューでは、ビューモデルの(ビューのモデル)ロールには、UIロジックとビューの状態があります

ビューモデルには、UIロジックや「ビューステート」を含めることはできません。この説明のために、ビューステートをスクロール位置、選択された行インデックス、選択されたインデックス、ウィンドウサイズなどとして定義します。これらはビューモデルに属しません。 SelectedIndexなどは、UIでのデータの表示方法に固有のものです(DataGridの並べ替え順序を変更すると、SelectedItemが同じでも、SelectedIndexが変更される可能性があります)。この特定の場合、SelectedItemはビューモデルにバインドできますが、SelectedIndexはバインドできません。
。 (前に述べたインターフェースを介して)viewmodelを呼び出します。ビューには、データがどのように保存されているかがわかりません。また、ビューモデルには、データがビューから送られてくることがわかりません(インターフェイスを介して呼び出しを公開しているだけです)。

そして、ビューの役割は、いくつかのコンテンツを表示し、ビューモデルを同期することです(データバインディングコードを持っています)

はい、ビューの責任は、単にビューモデルによって提示されるデータを視覚的に表示することです。ビューモデルはモデルからデータを取得します(モデルはデータベース呼び出しまたはWCF Webサービス呼び出しを行う役割を果たします。これは通常「サービス」を介して行われますが、それはまったく別の議論です)。ビューモデルは、データを整形または操作できます。つまり、すべての顧客のリストを取得できますが、ビューがバインドできるパブリックプロパティでそのリスト(現在の顧客である可能性があります)のフィルターバージョンのみを公開できます。
データを視覚的なものに操作する場合(一般的な例は列挙値が色に変換される場合)、ビューモデルにはまだ列挙値のみがあり、ビューはまだそれにバインドします値ですが、ビューも コンバータを使用 純粋なデータを視覚的な表現に変換します。コンバーターを使用することにより、ビューモデルはUI関連の操作を回避し、ビューは実際のロジックを回避します。

65
slugster

MVVMはコードとページデザインを完全に分割できます。コーダーはコーディングを重視し、デザイナーはデザインのみを重視します。だが:

  1. Blendを使用している、またはXAMLを理解しているデザイナーを見たことはありません。
  2. ほとんどすべてのXAMLは、コーダー自身が作成します。
8
user4276887

コードビハインドに本質的に悪いことは何もありません。単純な場合には、それを持っていることは問題ありません。ただし、多くのシナリオでUIロジックを管理するのは難しくなります。添付のビヘイビアとビューモデルにそのロジックをカプセル化することで、変数を分離(およびテスト)できるため、理解と保守が容易になります。

テスト容易性が懸念される場合は、ビューモデルと添付ビヘイビアにカプセル化できるUIロジックが多いほど、UIテストに頼らずに検証できるようになります。 (UIテストの必要性を完全に排除するわけではありませんが、より多くの時間/リソースを消費するUIテストに従事する前に、第1レベルの検証を提供します。

5
Michael Brown

引用されたセクションは、データの視覚化方法に関するものだと思います。たとえば、データの表示方法や場所に関連するコードビハインドでコードを記述しないでください(例:label1.Text = ...)。バインディングを使用してそのようなことを行うと、デザインとコードを分離しやすくなります(後のバージョンで「tbTest」という名前のテキストボックスにデータを表示する必要がある場合はどうなりますか?コードビハインドを変更する必要があります)。

彼らは、コードビハインドにコードを置くべきではないと言っているわけではありません。理想的な世界では、イベントに反応するか、そうでなければ処理できないデータを処理するだけだと言っているだけです。

少なくとも、それはあなたが引用したセクションから理解したことです。

2