MVVMは無意味ですか?[閉まっている]


91

正統なMVVM実装は無意味ですか?新しいアプリケーションを作成していて、WindowsフォームとWPFを検討しました。WPFを選択した理由は、将来性があり、柔軟性が高いためです。コードが少なく、XAMLを使用してUIに大幅な変更を加えるのが簡単です。

WPFの選択は明白であるため、ブレンド性、分離の懸念、および単体テスト性を提供するため、アプリケーションアーキテクチャとしてMVVMを使用することで、最大限に活用できると考えました。理論的には、UIプログラミングの聖杯のように美しく見えます。この短い冒険。しかし、本当の頭痛になっています。実際には、予想通り、ある問題を別の問題と交換していることがわかりました。私は、正しい結果を得て、より良いプログラマーになるために正しい方法で物事をやりたいという点で、強迫的なプログラマーになる傾向があります。MVVMパターンは、生産性に関する私のテストを失敗させ、大きな厄介なハックに変わりました!

明確な例は、モーダルダイアログボックスのサポートを追加することです。正しい方法は、ダイアログボックスを表示してビューモデルに関連付けることです。これを機能させるのは困難です。MVVMパターンを活用するには、アプリケーションのレイヤー全体のいくつかの場所にコードを配布する必要があります。また、テンプレートやランバ式などの難解なプログラミング構造を使用する必要があります。頭を掻いて画面を見つめるもの。これにより、最近発見したように、メンテナンスとデバッグの悪夢が起こります。2度目の呼び出しで例外が発生するまで、ダイアログボックスが閉じられるとダイアログボックスを再び表示できなくなると言って、aboutボックスは正常に機能していました。ダイアログウィンドウに閉じる機能のイベントハンドラーを追加する必要がありました。それのIDialogView実装の別のものと、IDialogViewModelの最後の別のもの。MVVMがそのような贅沢なハッカーから私たちを救ってくれると思いました!

この問題に対する競合する解決策を持っている人が何人かいますが、それらはすべてハックであり、クリーンで簡単に再利用できる、エレガントなソリューションを提供していません。ほとんどのMVVMツールキットはダイアログに光沢があり、ダイアログに対処する場合、それらは単なるカスタムボックスやビューモデルを必要としないアラートボックスです。

MVVMのビューパターン、少なくともその正統な実装をあきらめることを計画しています。どう思いますか?あなたが何かあったとしても、それはあなたにとって問題の価値がありましたか?私は単に無能なプログラマーなのでしょうか、それともMVVMが期待されているものではないのですか?


6
MVVMが過剰設計であるかどうかは常に疑問視してきました。興味深い質問です。
テイラーリース

11
MVVMやMVCのようなパターンは、いくつかの変更を行うか、コンポーネントを変更する必要があるまで、オーバーエンジニアリングのように見えます。あなたが最初にそれをしなければならないとき、式典
ロバートハーベイ、

41
ラムダは難解ですか?私へのニュース。
レイブイセン

5
@レイ-ハハ、そのコメントに+1!:D
Venemo

7
Alan Cooperが10年以上前にAbout Faceで指摘したように、UIとモーダルダイアログを設計しているのが適切なケースではない場合、おそらく何かがおかしいでしょう。
Robert Rossney、2011

回答:


61

私の答えが少し長くなったら申し訳ありませんが、私を責めないでください!あなたの質問も長いです。

要約すると、MVVMは無意味ではありません。

明確な例として、モーダルダイアログボックスのサポートが追加されています。正しい方法は、ダイアログボックスを表示してビューモデルに関連付けることです。これを機能させるのは困難です。

はい、そうです。
ただし、MVVMは、UIの外観をロジックから分離する方法を提供します。どこでもそれを使用することを強制する人は誰もいません。誰もがあなたの額に銃を構えて、すべてに対して個別のViewModelを作成することはありません。

これがこの特定の例に対する私のソリューションです
。UIが特定の入力を処理する方法は、ViewModelのビジネスではありません。ビューの.xaml.csファイルにコードを追加します。これにより、ダイアログボックスがインスタンス化され、同じViewModelインスタンス(または必要に応じて何か)がDataContextとして設定されます。

MVVMパターンを活用するには、アプリケーションのレイヤー全体のいくつかの場所にコードを配布する必要があります。また、テンプレートやランバ式などの難解なプログラミング構造を使用する必要があります。

まあ、いくつかの場所でそれを使用する必要はありません。これは私がそれを解決する方法です:

  • XAMLをビューに追加し、.xaml.csには何も追加しません
  • ViewModel内にすべてのアプリロジックを記述します(UI要素で直接動作するものを除く)
  • UIで実行する必要があるがビジネスロジックとは何の関係もないすべてのコードは、.xaml.csファイルに入ります

MVVMの目的は、主にアプリケーションのロジックと具象UIを分離することであり、したがってUIの簡単な変更(または完全な置き換え)を可能にすることだと思います。
私は次の原則を使用します。ビューは、ViewModelから必要なものをすべて認識して想定できますが、ViewModelはビューについて何も認識できません。
WPFは、まさにそれを実現するために使用できる素晴らしいバインディングモデルを提供します。

(ところで、テンプレートとラムダ式は、正しく使用すれば難解なものにはなりません。ただし、使用したくない場合は使用しないでください。)

頭を掻いて画面を見つめるもの。

ええ、私は気持ちを知っています。MVVMを最初に見たときに感じていたとおりのこと。しかし、コツをつかめば、もう悪くはありません。

私は約ボックスがうまく機能していた...

アバウトボックスの後ろにViewModelを配置するのはなぜですか?その意味はありません。

ほとんどのMVVMツールキットはダイアログに光沢があり、ダイアログに対処する場合、それらは単なるカスタムボックスやビューモデルを必要としないアラートボックスです。

はい、UI要素が同じウィンドウまたは別のウィンドウにある、あるいは現在火星を周回しているという事実自体は、ViewModelsの懸念事項ではありません。
関心事の分離

編集:

タイトルが「自分のMVVMフレームワークを構築する」です。見る価値があります。


2
最後の3ワードは+1。しかし、残りの答えも良いです。:)
ロバートハーヴェイ

12
分離コードの使用に関するアドバイスは+1。MVVMでコードビハインドを使用することは「悪い」というのはよくある誤解です。
トーマスレベスク

@トーマス:ええ、私はもっと同意できませんでした。「UIに関係するすべての」コードをすべてViewModelに配置するいくつかの実装を見てきました。それはかなりハックでした。
Venemo

3
@Venemo、カスタムビヘイビアなどのテクニックを使用して、コードビハインドに入れたいものの多くをカプセル化できると思います。これは、グルーコードを繰り返し作成している場合に便利です。ただし、一般的には、厄介なXAMLをハッキングするよりも、コードビハインドを使用して接着する方がよいと思います。私の心の中での主な懸念は、ユニットテストを保証するほど洗練されたコードビハインドに何もないことを確認することです。十分に複雑なものは、BehaviorやMarkupExtensionのように、ViewModelまたは拡張クラスにカプセル化する方が適切です。
ダンブライアント

7
@トーマス:正解です。MVVMの最大の神話は、MVVMの目的が分離コードを取り除くことであるということです。その目的は、UI以外のコードを背後のコードから取り除くことです。UIのみのコードをViewModelに配置するのは、問題のドメインコードをコードビハインドに配置するのと同じくらい悪いことです。
ジムレイネリ2011

8

これを機能させるのは困難です。MVVMパターンを活用するには、アプリケーションのレイヤー全体のいくつかの場所にコードを配布する必要があります。また、テンプレートやランバ式などの難解なプログラミング構造を使用する必要があります。

ありふれたモーダルダイアログボックスの場合 あなたは間違いなくそこで何か悪いことをしています-MVVMの実装はそれほど複雑である必要はありません。

あなたがMVVMとWPFの両方に不慣れであることを考えると、どこでも次善のソリューションを使用していて、不必要に複雑になっている可能性があります。少なくとも、私が初めてWPFに行ったときにそうしました。あきらめる前に、問題が本当にMVVMであり、実装ではないことを確認してください。

MVVM、MVC、Document-Viewなどは古いパターンのファミリーです。欠点はありますが、説明したような致命的な欠陥はありません。


5

私はPRISMを使用した非常に複雑なMVVM開発の真っ最中なので、すでにこの種の懸念に対処する必要がありました。

私の個人的な結論:

MVVM対MVC / PopUps&co

  • MVVMは本当に素晴らしいパターンであり、ほとんどの場合、WPFの強力なデータバインディングによりMVCを完全に置き換えます
  • プレゼンターからサービスレイヤーを直接呼び出すことは、ほとんどの場合、正当な実装です
  • {Binding Path = /}構文のおかげで、非常に複雑なList / Detailシナリオでも純粋なMVVMで実装できます
  • それにもかかわらず、複数のビュー間の複雑な調整を実装する必要がある場合、コントローラーは必須です
  • イベントを使用できます。IView(またはAbstractObserver)インスタンスをコントローラーに格納することを意味する古いパターンは廃止されました
  • コントローラは、IOCコンテナによって各Presenterに挿入できます
  • PrismのIEventAggregatorサービスは、コントローラーの唯一の使用がイベントディスパッチである場合の別の可能なソリューションです(この場合、コントローラーを完全に置き換えることができます)。
  • ビューが動的に作成される場合、これはコントローラーにとって非常に適したジョブです(プリズムでは、コントローラーはIRegionManagerに注入(IOC)されます)。
  • モーダルダイアログボックスは、必須の確認などの実際にブロックする操作を除いて、最近の複合アプリケーションではほとんど使用されていません。これらの場合、モーダルアクティベーションは、コントローラー内で呼び出されるサービスとして抽象化され、特殊なクラスによって実装されます。これにより、高度なプレゼンテーションレベルのユニットテストも可能になります。たとえば、コントローラーはIConfirmationService.RequestConfirmation( "are you sure")を呼び出します。これにより、実行時にモーダルダイアログ表示がトリガーされ、単体テスト中に簡単にモックできます。

5

私は不正行為によって対話の問題に対処します。MainWindowは、アプリケーション固有のすべてのダイアログを公開するIWindowServicesインターフェイスを実装しています。次に、他のViewModelでサービスインターフェイスをインポートし(MEFを使用しますが、インターフェイスをコンストラクターに手動で渡すだけで簡単にできます)、それを使用して必要なことを実行できます。たとえば、これは私のユーティリティアプリケーションのインターフェイスの外観です。

//Wrapper interface for dialog functionality to allow for mocking during tests
public interface IWindowServices
{
    bool ExecuteNewProject(NewProjectViewModel model);

    bool ExecuteImportSymbols(ImportSymbolsViewModel model);

    bool ExecuteOpenDialog(OpenFileDialog dialog);

    bool ExecuteSaveDialog(SaveFileDialog dialog);

    bool ExecuteWarningConfirmation(string text, string caption);

    void ExitApplication();
}

これにより、すべてのダイアログ実行が1か所に配置され、単体テスト用に簡単にスタブできます。ダイアログのクライアントが適切なViewModelを作成しなければならないというパターンに従います。ViewModelは必要に応じて構成できます。Execute呼び出しはブロックし、その後クライアントはViewModelの内容を見てダイアログの結果を確認できます。

より「純粋な」MVVM設計は、よりクリーンな断熱材とより複雑な構成が必要な大規模なアプリケーションでは重要かもしれませんが、中小規模のアプリでは、必要なフックを公開する適切なサービスを備えた実用的なアプローチで十分だと思います。


しかし、それをどこに呼びますか?ダイアログを渡すのではなく、IWindowServicesクラスの関数内でダイアログを作成する方が良いでしょう。そうすれば、呼び出し側のモデルビューは、特定のダイアログの実装について何も知る必要がなくなります。
Joel Rodgers、

インターフェイスは、アプリケーションダイアログへのアクセスが必要な私のViewModelインスタンスに注入されます。ほとんどの場合、ダイアログのViewModelを渡しますが、少し面倒になり、ファイルダイアログの呼び出しにWPF OpenFileDialogおよびSaveFileDialogを使用しました。私の主要な目標は、単体テストの目的での分離でした。そのため、その目標にはこれで十分です。より適切な分離が必要な場合は、ダイアログに必要なプロパティを複製するOpenFileViewModelおよびSaveFileViewModelを作成することをお勧めします。
ダンブライアント

ダイアログを使用しているViewModelが、開きたい各ダイアログの特定のViewModelを知っているという点で、これは完全に純粋なアプローチではないことに注意してください。これはかなりクリーンだと思いますが、ダイアログの使用に必要なパラメーターを純粋に公開するクラスで断熱材の追加レイヤーを常に追加し、バインディング中に使用されるViewModelプロパティの不必要な可視性を隠すことができます。小さいアプリケーションの場合、この追加の断熱材はやり過ぎだと思います。
ダンブライアント

5

デザインパターンは、あなたを助けるためのものであり、妨げるものではありません。優れた開発者であることのほんの一部は、「ルールを破る」タイミングを知ることです。MVVMがタスクにとって扱いにくく、将来の価値は努力に値しないと判断した場合は、パターンを使用しないでください。たとえば、他のポスターがコメントしているように、単純なaboutボックスを実装するためになぜすべてのオーバーヘッドを経験するのですか?

デザインパターンは、独断的に従うことを意図したものではありません。


2
正しい。シンプルなaboutボックスはシンプルでなければなりませんが、バージョン、ライセンス、実行中のプロセス、会社名などの情報を表示する必要がある場合はどうでしょうか。これはどこかにあるすべての情報です。標準形式では、そのすべての情報をバインドして、それで処理を行うことができます。MVVMは、そのためのビューモデルを作成する必要があると言っていますが、これは冗長です。
ATL_DEV '05 / 08/05

1

パターン自体としてMVVMは素晴らしいです。しかし、NET 4.0データバインディングサポートに付属するWPFの制御ライブラリは非常に制限されており、WinFormよりもはるかに優れていますが、それでもバインド可能なMVVMには十分ではありません。
バインド可能なMVVM:データバインディングのみを使用してViewModelがViewに接続されているUIです。
MVVMパターンはViewStateのオブジェクト表現に関するものであり、ViewとViewModelの間の同期を維持する方法を記述していません。WPFではデータバインディングですが、何でもかまいません。実際に、MVVMパターンは、events \ callbacksをサポートする任意のUIツールキットで使用できます。WinFormsの純粋なWinAPIで使用できます(私はそうでした。events\ callbacksでの作業はそれほど多くありません)。Textでも使用できます。コンソール、MVVMパターンを使用してDoSのノートンコマンダーを書き換える。

つまり、MVVMは無意味ではなく、すばらしいものです。NET 4.0 WPFの制御ライブラリはゴミです。

これは、WPFを使用して純粋なMVVMの方法でデータバインドできない単純な概念実証モデルです。

public class PersonsViewModel
{
    public IList<Person> PersonList;
    public IList<ColumnDescription> TableColumns;
    public IList<Person> SelectedPersons;
    public Person ActivePerson;
    public ColumnDescription SortedColumn;
}

WPFのDataGrid列ヘッダーをデータバインドしたり、選択した行をデータバインドしたりすることはできません。コードを単純な方法で行うか、これらの5行の最も単純なViewModelに対して200行のXAMLハックコードを記述します。複雑なViewModelで事態がさら​​に悪化することを想像するしかありません。
したがって、Hello Worldアプリケーションを作成していない限り、WPFでバインド可能なMVVMを使用しても意味がありません。ViewModelをバインドするためのハックにほとんどの時間を費やします。データバインディングは適切ですが、イベントの70%の時間にフォールバックする準備ができています。


これをコンバーターでDataGridにバインドできます。
Cameron MacFarland、2011

@CameronMacFarland:すべてではありません。一部のプロパティは読み取り専用でバインドできません。一部は存在せず、状態の変化を報告するイベントのみがあります。
Alex Burtsev、2011

WPF DataGridの使用経験があまりないことは認めます。醜く、WPFに適合しなくなったので、避けたいと思います。コンバーターとAttachedPropertiesを組み合わせてイベントを処理すると、必要なものが得られるはずです。
Cameron MacFarland、2011

1
アレックス、あなたが抱えている問題は、MVVMではなく、DataGridの設計にあります。「データバインディングは適切ですが、イベントの70%の時間にフォールバックする準備ができている」と言うのは単に間違っています。(Telerik)データグリッドが初期化に必要なイベントハンドラーを除いて、UIにイベントハンドラーがない、客観的に巨大なWPFアプリケーションをいくつか作成しました。
Robert Rossney、2011

3
「これはひどく設計されていて機能しない」という態度を採用する代わりに、「なぜこれが他の人には機能するが私には機能しないのか」と考えた方がより成功すると思います。物事を行うのが難しい理由は、まだ方法を知らないためです。
Robert Rossney、2011

0

いいえ、それは無意味ではありませんが、パターン自体は途方もなく単純ですが、あなたの頭を包むことは困難です。そこにはたくさんの誤った情報があり、適切な方法をめぐって戦うさまざまなグループがあります。WPFとSilverlightでは、MVVMを使用する必要があります。そうしないと、コーディングをやり直して、新しいモデルの問題を解決しようとするだけで、トラブルにつながる「古い」勝利フォームの方法論になります。すべてが非同期である必要があるため、これはSilverlightの場合に当てはまります(これを回避することは可能ですが、別のプラットフォームを選択する必要があります)。

この記事を読んで、ViewModelパターンを使用してWPF TreeViewを簡略化する 方法を注意深く読んで、MVVMを適切に実装し、勝利フォームの考え方をMVVMの新しい考え方に変える方法を確認してください。つまり、何かを実行したい場合は、まずロジックをビューではなくビューモデルに適用します。アイテムを選択しますか?アイコンを変更しますか?UI要素を繰り返し処理するのではなく、モデルのプロパティを更新して、データバインディングに細心の注意を払ってください。


-1

(モーダル)ダイアログに関して、多くのMVVM実装で同じ問題が発生しました。MVVMパターンの参加者を見ると、一貫性のあるアプリケーションを構築するために何かが足りないと感じています。

  • ビューには、特定のGUIコントロールが含まれ、ユーザーインターフェイスの外観を定義します。
  • ViewModelは、プレゼンテーションの状態と動作を表します。
  • モデルは、ドメインレイヤーのビジネスオブジェクト、または必要なデータを提供するサービスです。

しかし、不足しているのは:

  • 誰がViewModelを作成しますか?
  • アプリケーションワークフローの責任者は誰ですか?
  • 互いに通信する必要があるときに、誰がViewModelを仲介するのですか?

私のアプローチは、不足点の原因となる(ユースケース)コントローラーを導入することです。これがどのように機能するかは、WPFアプリケーションフレームワーク(WAF)サンプルアプリケーションで確認できます。


Josh Smithによって実装されたMediatorパターンは、すべてのView Model通信の問題を解決しました。Messenger.NotifyColleaguesは、2つのビューモデルがお互いを知らなくても、グローバルイベント(ケアされている場合)に応答する方法を知っている完全に独立したビューモデルを持つ方法を提供しました。もう数回ベーコンが保存されています。
JasonD
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.