MVCパターンをC#WinFormsアプリケーションに適用するにはどうすればよいですか?


11

私はそれ以来、MVCパターンを使用してGUIを設計しているC ++開発者です。

最近、C#に戻りたいと思い、Windowsフォームアプリケーションをセットアップしましたが、MVC準拠の構造にプッシュする方法が少し失われました。

私が現在やろうとしていることは、WinFormsに与えられたクラスをビューとして「宣言」し、モデルとコントローラーのクラスをバックグラウンドで追加することです。ただし、ボタンのクリックなど、イベントと対話する方法についてはよくわかりません。通常、これらのイベントをコントローラーにリダイレクトし、完了したらビューでアクションを実行します。

しかし、これはこの星座ではかなり不満を感じます。たとえば、「Exit」ボタンを実装する場合、ViewからControllerにイベントをリダイレクトする必要があります。また、Viewに追加のパブリックメソッドを実装し、それをControllerから呼び出すことができます。最初のインスタンスのViewからClose()を呼び出すだけです。

何かアドバイスはありますか?C#でのWindows Formsの私の理解は、MVC実装を試すにはまだ十分ではありませんか?フォームクラスに間違った役割を与えていますか?MVCはこのユースケースにとって単に不適切なアーキテクチャですか?


1
OTの質問。しかし、なぜWInformsなのでしょうか?WPFはWinformsを置き換えることを目的としており、MVC(まあ技術的にはMVVM)をサポートします。ただし、WPFの学習曲線は急勾配になる可能性があります。(あなたはひどくそれを行う場合がありますが、WinformsのようなWPFコードの外観を作ることができる)
ピーター・M

1
@PeterM:10年後でもWPFがひどく遅いためです。
-whatsisname

3
@whatsisnameのコメントを言い換えると、WPFはより大きなアプリケーションを対象としています。Winformsは間違いなくシンプルであるため、小さなアプリケーションの方がWinformsでより適切に処理される可能性があります。ただし、その引数を作成する場合は、WinformsアプリケーションがMVPを必要としないと思われるほど十分に小さいという引数を作成することもできます。MVVMはWPFに組み込まれています。WPFにはベクターベースのグラフィックスがあるため、Winformsと同じサイズ設定の問題はありません。WPFは非常に構成可能で(コントロールを他のコントロール内に簡単に配置できます)、キラーデータバインディングがあります。好きではないものは何ですか?
ロバートハーベイ

3
@whatsisname WPFは吸うかもしれないが、それは上とおもちゃのプログラム上何のためにはるかに少ないのWinforms以上吸う
ピーター・M

2
社内のデスクトッププログラムの場合、私はそう言うでしょう。しかし、多くの企業では、インストールが不要なという理由だけで、業務にブラウザーベースのアプリケーションを好んでいます。
ロバートハーヴェイ

回答:


3

偶然にも、MVCを模したWinFormsプロジェクトに取り組んでいます。これを完璧な答えとは言いませんが、全体的な設計について説明します。

このプロジェクトを開始する前に読んだことから、これを実装する「正しい」方法はないようです。単純なOOPとMVCの設計原則に従いましたが、残りは試行錯誤でワークフローを開発しました。

MVCはこのユースケースにとって単に不適切なアーキテクチャですか?

いいえ ..?あなたの質問には、それに対する直接的な答えを提供するのに十分な文脈がありません。そもそもMVCを使用しているのはなぜですか?プロジェクトの非機能要件は何ですか?あなたのプロジェクトは非常にUIが重いですか?セキュリティにもっと関心があり、むしろ階層化アーキテクチャが必要ですか?プロジェクトの主なコンポーネントは何ですか?おそらく、各コンポーネントには異なる設計パターンが必要です。そもそもこのデザインパターンを使用する理由を見つけてください。そうすれば、自分の質問に答えられるかもしれません;)

MVCを使用する理由:私の意見で理解するのはかなり単純なデザインパターンであり、私のデザインはユーザーの操作に大きく基づいています。MVCで開発者が懸念を分離できるようにする方法は、私のアプリケーションでも十分です。これにより、コードの保守性とテスト性向上します。

また、私はより多くのハイブリッド設計を使用していると思います。通常、ソフトウェアエンジニアリングで提示される理想的な概念は、実際には実際には機能しません。プロジェクトのニーズに合わせて設計を変更できます。善悪に巻き込まれる必要はありません。一般的な慣行はありますが、自分で足を撃たない限り、ルールは常に曲がったり壊れたりすることがあります。

私の実装は、必要なコンポーネントについてのアイデアを与えてくれた高レベルの設計から始まりました。この方法で開始し、アーキテクチャ内で作業を進めることが最善です。プロジェクトのパッケージ図は次のとおりです(StarUMLで作成): ここに画像の説明を入力してください

プレゼンテーションレイヤーを除くすべてのレイヤーがメッセージングシステムに依存していることに注意してください。これは、下位層とそれらの層のサブシステムが互いに通信するために使用する一般的な「言語」です。私の場合、実行可能な操作に基づいた単純な列挙でした。それは次のポイントに私をもたらします...

操作またはコマンドを実装の基礎と考えてください。アプリケーションで何をしたいですか?最も基本的な操作に分けてください。例:CreateProject、WriteNotes、SaveProject、LoadProjectなど。GUI(またはフォームクラス)で何らかのイベント(ボタンを押すなど)が発生します。すべての操作には、コントローラメソッドが関連付けられています。この場合、Exitのようなものは単純すぎます。アプリケーションは、Formクラスから単純に閉じることができます。しかし、最初にいくつかのアプリケーションデータをファイルに保存したいとしますか?ボタンを押すメソッド内で、それぞれのコントローラークラスから「保存」メソッドを呼び出します。

そこから、コントローラーはサービスクラスから正しい操作セットを呼び出します。アプリケーションのサービスクラスは、ドメインレイヤーへのインターフェイスとして機能します。コントローラのメソッド呼び出し(およびGUI)から受け取った入力を検証し、データモデルを操作します。

検証と対応するオブジェクトの操作が完了すると、サービスメソッドはメッセージコードをコントローラーに返します。たとえば、MessageCodes.SaveSuccess。コントローラクラスとサービスクラスの両方は、ドメインオブジェクトおよび/またはグループ化できる一般的な操作のセットに基づいていました。

例:(FileMenuController操作:NewProject、SaveProject、LoadProject)-> ProjectServices(CreateProject、PersistProjectToFile、LoadProjectFromFile)。Projectデータモデル内のドメインクラスはどこにありますか。私の場合、コントローラークラスとサービスクラスは、静的メソッドを持つインスタンス化不可能なクラスでした。

次に、コントローラーは、操作が完了しない/成功したと認識します。現在、コントローラーには、プレゼンテーション層と対話するために使用する独自のメッセージングシステムがあるため、サービス層とプレゼンテーション層の間の二重の依存関係があります。この場合ViewStateViewModelsパッケージで呼び出されたクラスは常にコントローラーによってGUIに返されます。この状態には、アプリケーションを有効にしようとした状態は?」、「実行しようとした操作に関する人間が読めるメッセージと、成功または失敗した理由(エラーメッセージ)」およびViewModelクラスなどの情報が含まれます。

このViewModelクラスには、GUIがビューの更新に使用するドメインレイヤーからの関連データが含まれています。これらのビューモデルはドメインクラスのように見えますが、私の場合は非常に細いオブジェクトを使用しました。基本的に、それらにはほとんど動作がなく、アプリケーションの下位レベルの状態に関する情報を中継するだけです。つまり、ドメインクラスをプレゼンテーション層に渡すことは決してありません。これはまた、ControllersServicesパッケージがサービスレイヤーを2つの部分に分割する理由でもあります。コントローラは、ドメインクラスを処理したり、状態を検証したりすることはありません。それらは、GUI関連データをサービスが使用できるドメイン関連データに変換する境界として機能し、逆もまた同様です。コントローラにサービスロジックを含めると、非常に太くなる 保守が難しいコントローラー。

これが出発点になることを願っています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.