SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

Presentation Modelパターンによる動的XAMLフォームの作成

WPFとPresentation Modelパターンを組み合わせたアプリケーション

ダウンロード サンプルソース (30.3 KB)

仕上げ

 ListViewの実質的な定義は完了しましたが、この記事では話を簡単にするために一部の重要なコードの説明を割愛しています。その部分の詳細については、サンプルコードをご覧ください。省略した部分のコードでは、IValueConverterを持つもう1つのDataTemplateを使用して、startDateTemplateのComboBoxに表示する日付のフォーマットを変更しています。

 既にListViewは定義されているので、XAMLのコードビハインドにイベントハンドラを追加することができます。これらのハンドラはExpenseLineItemを追加または削除する処理をExpenseSheetWindowModelに委譲します。そのためには、ユーザーが追加または削除しようとしているListViewItemのインデックス(ユーザーが[Add]ボタンまたは[Delete]ボタンをクリックした項目のインデックス)を調べて、そのインデックスの次の位置への行項目の挿入、またはそのインデックスの位置の行項目の削除を実行できるようにする必要があります。サンプルコードのaddButton_ClickおよびdeleteButton_Clickの2つのイベントハンドラでは、ビジュアルツリーを上にたどってListViewItemを見つけ出し、それをListViewのItemContentGeneratorメソッドに渡すことによってインデックスを取得しています。

筆者注
 ListViewItemのインデックスを調べる処理については、このスレッドでJosh Smith氏(MVP)から助言をいただきました。
private void addButton_Click(
   object sender, RoutedEventArgs e) {
   int index = GetListViewItemIndex(
      e.OriginalSource as DependencyObject);
   presentationModel.InsertRowIntoCurrentExpenseSheet(
      index + 1, new ExpenseLineItem());
}
   
private void deleteButton_Click(
   object sender, RoutedEventArgs e) {
   ItemCollection items = lineItemListView.Items;
   
   // don't delete last item
   if (items.Count == 1) { return; } 
   
   int index = GetListViewItemIndex(
      e.OriginalSource as DependencyObject);
   presentationModel.RemoveRowFromCurrentExpenseSheet(index);
}
   
private int GetListViewItemIndex(DependencyObject depObj) {
   while (!(depObj is ListViewItem)) {
      depObj = VisualTreeHelper.GetParent(depObj);
   }
   
   return lineItemListView.ItemContainerGenerator.
      IndexFromContainer(depObj);
}

 ハンドラから呼び出されるExpenseSheetWindowModelのメソッドは、ExpenseSheetに格納されているExpenseLineItemのObservableCollectionに対して要素を挿入または削除する単純な処理を行います。この処理の対象はObservableCollectionであるため、それが変更された時点でPropertyChangedイベントが発生し、UIが自動的に再描画されます。

public void RemoveRowFromCurrentExpenseSheet(int index) {
   CurrentExpenseSheet.LineItems.RemoveAt(index);
}
   
public void InsertRowIntoCurrentExpenseSheet(
   int index, ExpenseLineItem lineItem) {
   CurrentExpenseSheet.LineItems.Insert(index, lineItem);
}

基本原則の拡張的適用

 この記事では、複数の編集可能な行項目を持つ動的ユーザーインターフェイスを構築するうえでPresentation Modelがどのように有効であるのかを示しました。サンプルコードの内容をご覧になれば、図1の左上のナビゲーションボタン(緑色の3角形と正方形が表示されているボタン)など、この記事では取り上げなかったその他のUI要素も、ExpenseSheetWindowModelによって制御されていることがわかるでしょう。ここで説明した考え方は、行項目を表示するUIの開発だけにとどまらず、データセットに合わせて複数の編集可能コンポーネントをさまざまなレイアウトで表示することが必要なUIの開発に応用できます。

 Presentation Modelパターンを使用すると、ユーザーインターフェイスの状態と振る舞いをカプセル化することができます。この例のメソッドの本体はXAMLのコードビハインドに無理なく記述できるほど小さいので、Presentation Modelの導入は話を無駄に複雑にするだけではないかと考える人もいるでしょう。確かに、この例のように小さなアプリケーションの場合はそう言えるもしれませんが、構築するUIの規模が大きくなってくると、ロジックはたちまち複雑化して厄介なものとなります。さらに、その他の付加的な機能――たとえば時間のかかる処理のためのバックグラウンドスレッドの起動や、マウスカーソルの状態の設定、進捗インジケータやメッセージボックスの表示など――も必要となるので、コードは混沌として手に負えない状態に劣化し始めるでしょう。

 しかし、Presentation Modelを使用すれば、UIとビジネスオブジェクトを抽象化されたクリーンな形で結び付けることができるので、将来、まったく異なる別のUIの構築が必要となった場合でも、中核的なロジックを実装し直す必要なしにUIの変更を実現できます。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

John Wheeler(John Wheeler)

ComFrame Software Corporation(Southeastern Microsoft認定ゴールドパートナー、IBM Rationalパートナー)の上級ソフトウェアエンジニア。フルプロジェクト開発のスペシャリストで、.NETのほか、Java、Ruby on Rails、軽量開発手法...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/1708 2007/10/09 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー