winformでプロジェクトを適切に構成する方法は?


26

少し前にwinformアプリケーションの作成を開始しましたが、その時点ではそれは小さく、プロジェクトの構成方法については何も考えていませんでした。

それ以来、必要に応じて追加の機能を追加し、プロジェクトフォルダーはどんどん大きくなっています。今では、何らかの方法でプロジェクトを構成する時が来たと思いますが、適切な方法はわからないので、質問はほとんどありません。

プロジェクトフォルダを適切に再構築する方法は?

現時点では、次のようなことを考えています。

  • フォーム用のフォルダーを作成する
  • ユーティリティクラスのフォルダーを作成する
  • データのみを含むクラスのフォルダーを作成する

クラスを追加するときの命名規則は何ですか?

クラスの名前を見るだけで機能を識別できるように、クラスの名前も変更する必要がありますか?たとえば、すべてのフォームクラスの名前を変更して、名前がFormで終わるようにします。または、それらのための特別なフォルダが作成されている場合、これは不要ですか?

メインフォームのすべてのコードがForm1.csに収まらないようにするため

私が遭遇した別の問題は、追加する各機能でメインフォームがより大きくなっているため、コードファイル(Form1.cs)が非常に大きくなっていることです。たとえば、TabControlがあり、各タブには多数のコントロールがあり、すべてのコードはForm1.csになりました。これを避ける方法は?

また、これらの問題を扱っている記事や本を知っていますか?

回答:


24

よくある落とし穴に陥ったように見えますが、心配しないでください、それらは修正できます:)

最初に、アプリケーションを少し異なって見て、チャンクに分割する必要があります。チャンクを2方向に分割できます。最初に、UIコードから制御ロジック(ビジネスルール、データアクセスコード、ユーザー権利コードなど)を分離できます。次に、UIコードをチャンクに分割できます。

したがって、UIをチャンクに分割して、後半を最初に行います。これを行う最も簡単な方法は、ユーザーコントロールを使用してUIを構成する単一のホストフォームを作成することです。各ユーザーコントロールは、フォームの領域を担当します。そのため、アプリケーションにユーザーのリストがあり、ユーザーをクリックすると、その下のテキストボックスに詳細が入力されているとします。ユーザーリストの表示を管理する1人のユーザーコントロールと、ユーザーの詳細の表示を管理する別のユーザーコントロールを作成できます。

ここでの本当のトリックは、コントロール間の通信をどのように管理するかです。フォーム上の30のユーザーコントロールがすべて相互に参照をランダムに保持し、それらのメソッドを呼び出すことは望ましくありません。

したがって、各コントロールのインターフェイスを作成します。インターフェイスには、コントロールが受け入れる操作と発生するイベントが含まれます。このアプリについて考えるとき、リストボックスリストの選択が変わってもかまいません。新しいユーザーが変わったという事実に興味があります。

したがって、サンプルアプリを使用すると、ユーザーのリストボックスをホストするコントロールの最初のインターフェイスには、ユーザーオブジェクトを渡すUserChangedというイベントが含まれます。

リストボックスに飽きて3Dズームマジックアイコントロールが必要な場合は、同じインターフェイスにコーディングしてプラグインするだけなので、これは素晴らしいことです。

では、パート2、UIロジックをドメインロジックから分離します。さて、これは使い古されたパスなので、ここでMVPパターンを確認することをお勧めします。本当に簡単です。

各コントロールは、現在ビュー(MVPのV)と呼ばれ、上記で必要なもののほとんどを既にカバーしています。この場合、コントロールとそのインターフェイス。

追加するのは、モデルとプレゼンターだけです。

モデルには、アプリケーションの状態を管理するロジックが含まれています。知っていることは、ユーザーを取得するためにデータベースに行き、ユーザーを追加するときにデータベースに書き込むなどです。アイデアは、他のすべてから完全に隔離して、これらすべてをテストできることです。

プレゼンターの説明はもう少し複雑です。これは、モデルとビューの間に位置するクラスです。ビューによって作成され、ビューは前述のインターフェイスを使用してプレゼンターに渡されます。

プレゼンターは独自のインターフェイスを持つ必要はありませんが、とにかくインターフェイスを作成するのが好きです。プレゼンターに明示的にさせたいことを行います。

そのため、プレゼンターは、ユーザーのリストを取得するためにビューが使用するListOfAllUsersのようなメソッドを公開します。あるいは、AddUserメソッドをビューに配置して、プレゼンターから呼び出すこともできます。私は後者を好む。そうすることで、プレゼンターはユーザーを必要に応じてリストボックスに追加できます。

プレゼンターにはCanEditUserなどのプロパティもあります。これは、選択したユーザーが編集できる場合にtrueを返します。ビューは、知る必要があるたびにクエリを実行します。編集可能なものは黒で、読み取り可能なものは灰色で読みたい場合があります。技術的には、UIがフォーカスされているため、Viewの決定です。ユーザーが最初に編集可能かどうかはプレゼンター用です。プレゼンターは、モデルと話すため知っています。

要約すると、MVPを使用します。Microsoftは、私が説明した方法でMVPを使用するSCSF(スマートクライアントソフトウェアファクトリー)と呼ばれるものを提供しています。他にも多くのことが行われます。それは非常に複雑であり、彼らがすべてを行う方法が好きではありませんが、それは役立つかもしれません。


8

個人的には、すべてを1つの実行可能ファイルにまとめるのではなく、複数のアセンブリ間で異なる関心領域を分離することを好みます。

通常、アプリケーションのエントリポイントには絶対最小限のコードを保持することを好みます。ビジネスロジック、GUIコード、データアクセス(データベース/ファイルアクセス/ネットワーク接続など)はありません。通常、エントリポイントコード(つまり、実行可能ファイル)は、

  • すべての依存アセンブリからのさまざまなアプリケーションコンポーネントの作成と初期化
  • アプリケーション全体が依存するサードパーティコンポーネントの構成(例:診断出力用のLog4Net)
  • また、メイン関数に「すべての例外をキャッチしてスタックトレースを記録する」タイプのコードを含めると、予期しない重大/致命的な障害の状況を記録できます。

アプリケーションコンポーネント自体については、通常、小さなアプリケーションで少なくとも3つを目指しています。

  • データアクセスレイヤー(データベース接続、ファイルアクセスなど)-アプリケーションで使用される永続データ/保存データの複雑さに応じて、これらのアセンブリがいくつか存在する可能性があります-データベース処理用に別のアセンブリを作成する可能性があります(おそらく複数データベースとやり取りする場合、複雑なものが関係する場合のアセンブリ-たとえば、設計が不適切なデータベースを使用している場合は、コードでDB関係を処理する必要があります。したがって、挿入および取得のために複数のモジュールを記述することは理にかなっています)

  • ロジック層-アプリケーションを機能させるすべての決定とアルゴリズムを含むメインの「肉」。これらの決定は、GUI(GUIがあると言う人)についてまったく何も知らないはずです。うまく設計されたロジックレイヤーは、再コンパイルせずに「取り込んで」別のアプリケーションにドロップすることができます。複雑なアプリケーションでは、これらのロジックアセンブリが多数ある場合があります(アプリケーションの残りの部分に沿ってドラッグせずに「ピース」を切り取りたい場合があるため)

  • プレゼンテーション層(GUI); 小さなアプリケーションでは、いくつかのダイアログボックスを持つ単一の「メインフォーム」があり、すべてが単一のアセンブリに入ることができます。大きなアプリケーションでは、GUIの機能部分全体に個別のアセンブリがあります。ここでのクラスは、ユーザーインタラクションを機能させる以上のことは行いません。基本的な入力検証、アニメーションの処理などを行うシェルにすぎません。「何かをする」イベント/ボタンクリックはすべて転送されますロジックレイヤー(したがって、プレゼンテーションレイヤーにはアプリケーションロジックがまったく含まれませんが、ロジックレイヤーにGUIコードの負担をかけることもありません。そのため、プログレスバーやその他の凝ったものもプレゼンテーションアセンブリ/ ies)

プレゼンテーション、ロジック、およびデータレイヤーを別々のアセンブリに分割する主な理由は次のとおりです。データベースまたはGUIなしでメインアプリケーションロジックを実行できることが望ましいと感じています。

別の言い方をすれば、アプリケーションとまったく同じように動作するが、コマンドラインインターフェイスまたはWebインターフェイスを使用する別の実行可能ファイルを作成する場合。データベースストレージをファイルストレージ(または別の種類のデータベース)に交換します。メインアプリケーションのロジックにまったく触れる必要なく、そうすることができます-必要なのは、コマンドラインツールを少し書くだけですそして、別のデータモデルを使用して、「すべて一緒に接続」し、準備ができました。

あなたは「まあ私はそれをやりたくないので、これらのものを交換できないかどうかは関係ない」と考えているかもしれません-本当のポイントは、モジュール式アプリケーションの特徴の1つが「チャンク」を抽出し(何も再コンパイルする必要なし)、それらのチャンクを別の場所で再利用する機能。このようなコードを書くためには、一般に設計原則について長く真剣に考える必要があります-あなたはより多くのインターフェースを書くことを考え、さまざまなSOLID原則のトレードオフについて慎重に考える必要があります(同じBehaviour-Driven-DevelopmentまたはTDDの場合と同じように)

時々、既存のモノリシックなコードの塊からこの分離を達成するのは少し苦痛であり、多くの注意深いリファクタリングが必要です-それは問題ありません。他の方法に戻って、物事を再びまとめ始める(反対方向に行きすぎると、それらのアセンブリをそれ自体では役に立たないようにする効果があります)


4

フォルダ構造に従って、あなたが提案したことは一般にOKです。リソース用のフォルダーを追加する必要がある場合があります(複数の言語をサポートするためにリソースの各セットがISO言語コードの下にグループ化されるようにリソースを作成する場合があります)、画像、データベーススクリプト、ユーザー設定(リソースとして扱わない場合)、フォント、外部dll、ローカルdllなど

クラスを追加するときの命名規則は何ですか?

もちろん、フォームの外で各クラスを分離する必要があります。クラスごとのファイルもお勧めします(たとえば、MSはEF用に生成されたコードではそうしませんが)。

多くの人が意味のある短い名詞を複数形で使用しています(例:顧客)。一部は、対応するデータベーステーブルの単数名に近い名前を取得します(オブジェクトとテーブル間で1-1マッピングを使用する場合)。

クラスの命名には多くのソースがあります。たとえば、.net命名規則とプログラミング標準-ベストプラクティスまたはSTOVF-C#コーディングガイドラインをご覧ください。

メインフォームのすべてのコードがForm1.csに収まらないようにするため

ヘルパーコードは1つ以上のヘルパークラスに移動する必要があります。ユーザー設定をグリッドに適用するなど、GUIコントロールに非常に一般的な他のコードは、フォームから削除してヘルパークラスに追加するか、問題のコントロールをサブクラス化し、そこで必要なメソッドを作成することができます。

MS Windows Formsのイベントアクションの性質により、あいまいさと労力を追加せずにメインフォームからコードを削除するのに役立つことを私が知っていることはありません。ただし、MVVMは(将来のプロジェクトで)選択できる場合があります。たとえば、MVForm for Windows Formsを参照してください。


2

MVPは、大規模なビジネスアプリケーションのすべてであるプレゼンテーションロジックの整理に役立つため、オプションとして検討してください。実際には、アプリロジックは主にデータベースに存在するため、ビジネスコードをネイティブコードで実際に記述する必要はほとんどなく、適切に構造化されたプレゼンテーション機能のみが必要です。

MVPのような構造では、プレゼンターまたは必要に応じてコントローラーのセットが作成され、相互に調整され、UIやコードビハインドのものと混合しません。同じコントローラーで異なるUIを使用することもできます。

最後に、単純なリソースの整理、コンポーネントの分離、IoCとDIによる依存関係の指定、およびMVPアプローチにより、一般的な間違いや複雑さを回避し、時間通りに提供され、変更に対応できるシステムを構築するための鍵が提供されます。


1

プロジェクトの構造はプロジェクトとそのサイズに完全に依存しますが、いくつかのフォルダーを追加できます。

  • 共通(含まれるクラス、たとえばユーティリティ)
  • DataAccess(sqlまたは使用している他のデータベースサーバーを使用したデータのアクセスに関連するクラス)
  • スタイル(プロジェクトにCSSファイルがある場合)
  • リソース(画像、リソースファイルなど)
  • ワークフロー(ワークフローに関連するクラスがある場合)

フォームをあらゆる種類のフォルダに配置する必要はありません。フォームの名前を適宜変更してください。私はその常識を意味しますが、誰もあなたよりもあなたのフォームの方が良い名前を知っています。

命名規則は、クラスが「Hello World」メッセージを出力する場合、クラス名はタスクに関連するもので、クラスの適切な名前はHelloWorld.csである必要があります。

リージョンも作成できます

#region Hello そして endregion最後に出ます。

タブ用のクラスを作成できます。できることは間違いありません。最後にできることは、可能な場合はコードを再利用することです。

本?あー

各プロジェクトは異なるため、プロジェクトの構造を説明する本はありません。これらの種類のことは経験によって学びます。

お役に立てば幸いです!

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