GUIを設計および実装するための何らかの体系的な戦略はありますか?


18

Visual Studioを使用して、C#でGUIアプリケーションを作成しています。ツールボックスは気の利いたコンポーネントパレットとして機能し、ボタンやその他の要素(わかりやすくするために「コントロール」を意味する場合はボタンと呼びます)をフォームに簡単にドラッグアンドドロップできます。ただし、2つの問題が発生します。

  • そもそもボタンを作成するのは大変です。静的ではないフォームがある場合(つまり、ユーザーの操作に応じて実行時にボタンまたはその他のコントロールが作成される)、パレットをまったく使用できません。代わりに、使用しているメソッドでコンストラクターを呼び出して各ボタンを手動で作成し、ボタンの高さ、幅、位置、ラベル、イベントハンドラーなどを指定して手動で初期化する必要があります。フォームがどのように見えるかを確認することなく、これらのすべての化粧パラメータを推測する必要があるため、これは非常に退屈です。また、各ボタンに対して多くの行の反復コードを生成します。
  • ボタンに何かをさせるのも大変です。フル機能のアプリケーションでイベントを処理することは大きな苦痛です。私がこれを行う方法を知っている唯一の方法は、ボタンを選択し、そのプロパティのイベントタブに移動し、イベントをクリックしてOnClickイベントFormのコードを生成し、イベントの本文を入力することです。ロジックとプレゼンテーションを分離したいので、イベントハンドラーはすべて、適切なビジネスロジック関数の単一行呼び出しになります。しかし、これを多くのボタンに使用すると(たとえば、MS Wordなどのアプリケーションに存在するボタンの数を想像してください)、数Form十の定型イベントハンドラーメソッドでmyのコードを汚染し、これを維持するのは困難です。

これらのため、Hello Worldよりも複雑なGUIプログラムは、実際に作成するのは非常に非現実的です。明確にするために、最小限のUIを使用して作成するプログラムの複雑さを扱うことには何の問題もありません。ビジネスロジックコードをきちんと構築するために、かなりの能力を備えたOOPを使用できると感じています。しかし、GUIを開発するとき、私は立ち往生しています。とても退屈だと思うので、私は車輪を再発明しているように感じます。また、読んでいないGUIを適切に行う方法を説明する本がどこかにあります。

何か不足していますか?または、すべてのC#開発者は、繰り返しイベントハンドラーとボタン作成コードの無限のリストを受け入れるだけですか?


(うまくいけば役立つ)ヒントとして、良い答えが語れると期待しています:

  • OOP手法(ファクトリーパターンなど)を使用して、繰り返しボタンの作成を簡素化する
  • 多くのイベントハンドラを単一のメソッドに結合し、Senderどのボタンがそれを呼び出したかを判断し、それに応じて動作する単一のメソッド
  • XAMLおよびWindowsフォームの代わりにWPFを使用

もちろん、これらのいずれにも言及する必要はありません。どんな種類の答えを探しているのかということに関しては、最善の推測です。


私がそれを見るように、ファクトリーは良いパターンですが、イベントの代わりにコントロールにフックされたコマンドを持つModel-View-Controllerパターンがはるかに多く見られます。WPFは通常MVVMですが、MVCも可能です。現在、90%でMVCを使用するWPFに巨大なソフトウェアがあります。すべてのコマンドはコントローラーに転送され、彼はすべてを処理します
フランク

GUIエディターですべての可能なボタンを使用して動的フォームを作成し、動的に不必要なものを非表示にすることはできませんか?はるかに少ない作業のように聞こえます。
ハンスピーターシュター

@hstoerrしかし、レイアウトを機能させるのは難しいでしょう。多くのボタンが重複します。
スーパーベスト

回答:


22

あなたが言及したこれらの問題に対処するために長年にわたって進化したいくつかの方法論があります。これは、UIフレームワークが近年対処しなければならない2つの主要な問題です。WPFのバックグラウンドから来て、これらは次のようにアプローチされます。

命令型ではなく宣言型設計

コントロールをインスタンス化し、プロパティを設定するために苦労してコードを記述することを説明するとき、UIデザインの必須モデルを説明しています。WinFormsデザイナーでも、そのモデルのラッパーを使用しているだけです。Form1.Designer.csファイルを開くと、そこにあるすべてのコードが表示されます。

WPFとXAML(およびHTML以降の、もちろん他のフレームワークの同様のモデル)を使用すると、レイアウトを記述し、フレームワークがそれを実装するための重い作業を行うことが期待されます。Panel(Grid、WrapPanelなど)などのよりスマートなコントロールを使用してUI要素間の関係を記述しますが、手動で配置しないことが期待されます。ASP.NETのRepeaterやWPFのItemsControlなどの繰り返し可能なコントロールなどの柔軟な概念は、繰り返しコードを記述することなく動的にスケーリングするUIを作成し、動的に成長するデータエンティティを動的にコントロールとして表現できるようにします。

WPFのDataTemplatesを使用すると、宣言的に-UIの良さの小さなナゲットを定義し、それらをデータに一致させることができます。たとえば、CustomerデータオブジェクトのリストはItemsControlにバインドされ、通常の従業員(名前と住所を含む標準のグリッド行テンプレートを使用)かPrime Customerかによって異なるデータテンプレートが呼び出されますが、異なるテンプレート、写真付きでアクセスしやすいボタンが表示されます。繰り返しますが、特定のウィンドウにコードを記述することなく、データコンテキストを認識しているスマートなコントロールだけで、データに単純にバインドして関連する操作を実行できます。

データバインディングとコマンド分離

データバインディングに触れると、WPFのデータバインディング(AngularJSなどの他のフレームワークでも同様)を使用すると、コントロール(テキストボックスなど)をデータエンティティ(顧客名など)にリンクして意図を表明でき、フレームワークは配管を処理します。ロジックも同様に処理されます。コードビハインドイベントハンドラーをコントローラーベースのビジネスロジックに手動で接続する代わりに、データバインディングメカニズムを使用して、コントローラーの動作(ボタンのCommandプロパティなど)をアクティビティのナゲットを表すCommandオブジェクトにリンクします。

これにより、毎回イベントハンドラを書き換えることなく、このコマンドをウィンドウ間で共有できます。

より高いレベルの抽象化

2つの問題に対するこれらのソリューションはどちらも、当然のことながら面倒なWindowsフォームのイベント駆動型パラダイムよりも高い抽象化レベルへの移行を表しています。

これは、コントロールが持つすべてのプロパティ、およびボタンのクリック以降のすべての動作をコードで定義したくないという考え方です。コントロールと基礎となるフレームワークがより多くの作業を行い、データバインディング(WinFormsに存在しますが、WPFほど有用ではない)とUI間のリンクを定義するコマンドパターンのより抽象的な概念を考えることができます。そして金属に降りることを必要としない行動。

MVVMパターンは、このパラダイムに対するMicrosoftのアプローチです。私はそれを読むことをお勧めします。

これは、このモデルの外観と、コードの時間と行を節約する方法の大まかな例です。これはコンパイルされませんが、疑似WPFです。:)

アプリケーションリソースのどこかで、データテンプレートを定義します。

<DataTemplate x:DataType="Customer">
   <TextBox Text="{Binding Name}"/> 
</DataTemplate>

<DataTemplate x:DataType="PrimeCustomer">
   <Image Source="GoldStar.png"/>
   <TextBox Text="{Binding Name}"/> 
</DataTemplate>

次に、メイン画面を、データを公開するクラスであるViewModelにリンクします。たとえば、Customersのコレクション(単にa List<Customer>)とCommandオブジェクト(再び、typeの単純なパブリックプロパティICommand)とします。このリンクはバインディングを許可します:

public class CustomersnViewModel
{
     public List<Customer> Customers {get;}
     public ICommand RefreshCustomerListCommand {get;}  
}

およびUI:

<ListBox ItemsSource="{Binding Customers}"/>
<Button Command="{Binding RefreshCustomerListCommand}">Refresh</Button>

以上です。ListBoxの構文は、ViewModelから顧客のリストを取得し、それらをUIにレンダリングしようとします。前に定義した2つのDataTemplatesのため、関連するテンプレート(PrimeCustomerがCustomerから継承すると仮定して、DataTypeに基づいて)をインポートし、ListBoxのコンテンツとして配置します。ループ、コードを介したコントロールの動的生成はありません。

同様に、Buttonには、その動作をICommand実装にリンクする既存の構文があります。ICommand実装は、おそらくCustomersプロパティを更新することを知っており、データバインディングフレームワークにUIを自動的に更新するように促します。

もちろん、ここではいくつかのショートカットを取りましたが、これがその要点です。


5

まず、この記事シリーズをお勧めします:http : //codebetter.com/jeremymiller/2007/07/26/the-build-your-own-cab-series-table-of-contents/-詳細な問題には対処していませんボタンコードを使用しますが、独自のアプリケーションフレームワーク、特にGUIアプリケーションを設計および実装するための体系的な戦略を提供し、MVC、MVP、MVVMを典型的なFormsアプリケーションに適用する方法を示します。

「イベントの処理」に関する質問に対処します。同様の方法で動作するボタンを持つフォームが多数ある場合は、おそらく「アプリケーションフレームワーク」にイベントハンドラーの割り当てを実装するだけで十分です。GUIデザイナーを使用してクリックイベントを割り当てる代わりに、「クリック」ハンドラーに特定の名前のボタンの名前を付ける方法の命名規則を作成します。たとえばMyNiftyButton_ClickHandler、ボタンのボタンの場合MyNiftyButton。その後、フォームのすべてのボタンを反復処理する再利用可能なルーチン(リフレクションを使用)を作成し、フォームに関連するクリックハンドラーが含まれているかどうかを確認し、ハンドラーをイベントに自動的に割り当てることはそれほど難しくありません。こちらをご覧ください例を。

また、ボタンの束に対してイベントハンドラーを1つだけ使用したい場合も可能です。各イベントハンドラーには送信者が渡され、送信者は常に押されたボタンであるため、各ボタンの "Name"プロパティを利用してビジネスコードにディスパッチできます。

ボタン(または他のコントロール)を動的に作成する場合:テンプレートを作成するためだけに、未使用のフォームでデザイナーとボタンまたは他のコントロールを作成できます。次に、リフレクション(についてはこちらを参照)を使用してテンプレートコントロールを複製し、場所やサイズなどのプロパティのみを変更します。これはおそらく、コードで手動で2つまたは3つのプロパティを初期化するよりもはるかに簡単です。

Winformsを念頭に置いてこれを記述しました(私が推測するとおり)が、一般的な原則は、同様の機能を持つWPFのような他のGUI環境にも当てはまるはずです。


確かにWPFで実行でき、さらに簡単です。コマンドのリスト(特定の機能を事前にコーディングしたもの)を入力し、ウィンドウにソースを設定するだけです。素敵でシンプルなビジュアルテンプレートを作成し、必要なコマンドをコレクションに入力するだけで、残りは素晴らしいWPFバインディングによって視覚的に処理されます。
フランク
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.