あなたが言及したこれらの問題に対処するために長年にわたって進化したいくつかの方法論があります。これは、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を自動的に更新するように促します。
もちろん、ここではいくつかのショートカットを取りましたが、これがその要点です。