以前にMVVM(Model-View-ViewModel)フレームワークのPrismとSPREAD for WPFを題材にして3つの記事を公開しましたが、今回は、その記事の中で3番目にご紹介した別のViewをポップアップする方法を、「ComponentOne(コンポーネントワン)」の「FlexGrid for WPF(フレックスグリッド)」でも試してみたいと思います。
1. 使用するPrismの機能
MVVMパターンのアプリケーション開発を支援するPrismの機能のうち、今回は次の5つを使って簡単なサンプルを作成します。
- ViewModel の実装を補佐してくれる機能
- アプリケーション全体で使用できるDIコンテナ機能
- 名前付き表示領域を管理するRegion / Navigation機能
- DLLによるプラグイン実装をサポートするModule機能
- ViewModelとViewの間で通信を行うInteractionRequest機能
この記事のサンプルで子画面をポップアップするときに利用しているのが、5番目の「InteractionRequest」の機能です。親画面のFlexGridのアクティブ行を特定する情報を子画面に渡すためにこの機能を使っています。
ここで簡単に用語について説明しておきます。
- Shell:Moduleを読み込むWindow(またはWindowが含まれているプロジェクト)
- Module:Shell内のWindowに配置するViewを含んだDLL(またはプロジェクト)
- Region:Viewの配置先となるWindow内のContentControl
- Navigation:Region にViewを追加・削除する操作
- View:WindowまたはUserControl
Prismの詳細については、下記をご参照ください。
ホームページ:http://prismlibrary.github.io/
サンプル:https://github.com/PrismLibrary/Prism-Samples-Wpf
【メモ】
今回使っている「InteractionRequest」の機能がPrismサンプルの
28-CustomRequest
に実装されているので、ご確認いただければと思います。
2. 作成するサンプルの概要
サンプルの機能
サンプルに配置している各ボタンの機能は、次のとおりです。
- Viewの表示:FlexGridが配置されているViewを表示します
- Viewの非表示:FlexGridが配置されているViewを非表示にします
- 明細の表示:明細画面をポップアップします
- 戻る:子画面を閉じて親画面に戻ります
最初の2つのボタンはShellのWindow
に配置されており、3つ目のボタンはModule内の親画面用のUserControl
にFlexGridと一緒に配置されています。最後のボタンは、Module内の明細画面用のUserControl
にFlexGridと一緒に配置されています。
データの構成
モデルに含まれるデータソースは、親画面のFlexGridに表示されるOutline
テーブルと、明細画面のFlexGridに表示されるDetail
テーブルから構成されています。本来、これらのテーブルは、データベース内の正規化された複数のテーブルから作成されますが、ここでは直接これらのテーブルを作成しています。
各テーブルのフィールドは、次のとおりです。
- Outline:Class(分類)+Quantity(数量)+Amount(金額)
- Detail:Code(コード)+Name(品名)+Price(単価)+Class(分類)+Quantity(数量)+Amount(金額)
サンプルの構造
ShellのMainWindow(Window
)には、別プロジェクトのModuleに含まれているViewA(UserControl
)が配置され、そのViewA上にはOutlineテーブルを表示するFlexGridがあります。また、同じModule内にあるDetail(UserControl
)にはDetailテーブルを表示するFlexGridが配置されており、ViewAからポップアップされます。
また、Shell内にあるデータソースをModule内の2つのFlexGridに連結するために、PrismのDIコンテナ機能を使ってデータソースのインスタンスをコンテナに登録し、それをModule内のViewAViewModelとDetailViewModelのコンストラクタで取得しています。
MVVMの構成は次のようになっています。
- モデル:ProductModel.cs(Shell)
- ビュー:MainWindow.xaml(Shell)とViewA.xaml(Module)およびDetail.xaml(Module)
- ビューモデル:MainWindowViewModel.cs(Shell)とViewAViewModel.cs(Module)およびDetailViewModel.cs(Module)
このサンプルでは、次の点を考慮して、できるだけ「イベントハンドラとコードビハインドよりもXAMLに記述する」ようにしています。
- テスト容易性
- 再利用性
- 可読性
3. メインプロジェクト(Shell)の作成
ShellとなるメインプロジェクトのFlexGridWPF_Prism
は、次の手順で作成します。
これらの手順に先立ってPrismのテンプレートである「Prism Template Pack」を開発環境にインストールしておく必要があります。
「Prism Template Pack」のインストールについては、下記の記事で詳しく手順を解説しているので、そちらをご参照ください。
プロジェクトの生成
最初に、Prismのテンプレートを使ってShellとなるメインプロジェクトを作成します。
- Visual Studioを起動する
- [スタートページ]-[新しいプロジェクト]の検索欄に「prism」と入力する
- 表示されたリストから「Prism Blank App (WPF) C#」を選択する
- プロジェクトの保存先とプロジェクト名(FlexGridWPF_Prism)を指定する
- 表示された[PRISM PROJECT WIZARD]で「Unity」を選択して[CREATE PROJECT]ボタンをクリックする
- メニューの[ビルド]-[ソリューションのリビルド]を選択する
以上の操作でPrismのShellプロジェクトが自動的に生成されます。
モデル(ProductModel)の作成
先ほど作成したプロジェクトに「ProductModel」という名前の新規クラスを追加して、次のコードを記述します。
データのクラスにObservableCollection<>
の派生クラスが使われることがありますが、ここでは、データソースとして前述の2つのDataTable
を含むDataSet
を使っています。また、外部からこのDataSetを取得するためにGetSalesメソッドを用意しています。
ビュー(MainWindow)の作成
次の手順でViews
フォルダ内のMainWindow
ビューを変更します。各プロパティの設定内容については、下のXAMLを参照してください。
- Windowの各プロパティを設定します
- デフォルトで追加されているGridを削除します
- DockPanelを貼り付けます
- DockPanelのプロパティを設定します
- DockPanel内にStackPanelを貼り付けます
- StackPanelのプロパティを設定します
- StackPanel内に2つのButtonを貼り付けます
- 各Buttonのプロパティを設定します
- StackPanelの下にContentControlを貼り付けます
- ContentControlのプロパティを設定します
以上の操作を行ってMainWindow
のXAMLを次のようにします。
左のButton:
CommandParameter
に設定した”ViewA”を引数にしてMainWindowViewModel
のNavigateCommand
メソッドを呼び出します。その結果、この後で作成するModuleのViewA
がContentControl
に読み込まれ、MainWindow
上に表示されます。
右のButton:
空文字を引数にしてMainWindowViewModel
のNavigateCommand
メソッドを呼び出すことで、表示したViewA
を削除します。
FlexGridのライセンスを生成し、プロジェクトへ参照を追加するため、C1FlexGridコントロールをContentControlの下に貼り付け、すぐに削除しておきます。
ビューモデル(MainWindowViewModel)の作成
ビューモデルは、Prismのテンプレートが自動で生成するViewModels
フォルダにあるMainWindowViewModel.cs
に次のように記述します。
ビューモデルに実装する機能は、次のとおりです。
- Navigationを実現するために必要なIRegionManagerの取得
- Region / Navigation機能を実行するNavigateCommandとNavigateメソッド
なお、MainWindowViewModel
のコンストラクタで取得しているIRegionManager
は、Prismが自動的に設定します。
Shell機能の実装
Shellの基本機能を実装するために、Shell側で行う重要なステップがもう1つあります。
ここに追加するコードは、FlexGridWPF_Prismプロジェクト(Shell)にNavigationプロジェクト(Module)を参照設定している必要があります。
そのため、ここに記載している内容は、次の「4. モジュールプロジェクト(Module)の作成」を行った後で実装してください。
ここでは、次の2つのメソッドを追加することで、Shellの重要な機能を実装します。
- RegisterTypesメソッド:モデル(ProductModel)で取得したデータのインスタンスのコンテナへの登録
- ConfigureModuleCatalogメソッド:Module(NavigationModule)の読み込み
具体的には、プロジェクトに自動生成されるApp.xaml.cs
に次のように記述します。
4. モジュールプロジェクト(Module)の作成
- プロジェクトの追加
- ビュー(ViewA)の作成
- ビューモデル(ViewAViewModel)の作成
- ユーザーコントロールの追加
- ビュー(Detail)の作成
- ビューモデル(DetailViewModel)の作成
- Module機能の実装
プロジェクトの追加
次の手順で、PrismテンプレートのModuleプロジェクトをソリューションに追加します。
- Visual Studioのメニューで[ファイル]-[追加]-[新しいプロジェクト]を選択する
- 表示されたリストから「Prism Module (WPF) 」を選択する
- プロジェクト名(Navigation)を指定する
- [OK]ボタンをクリックする
- メニューの[ビルド]-[ソリューションのリビルド]を選択する
ビュー(ViewA)の作成
次の手順でViews
フォルダ内のViewA
ビューを変更します。各プロパティの設定内容については、下のXAMLを参照してください。
- UserControlの各プロパティを設定します
- デフォルトで追加されているGrid内のTextBlockを削除します
- GridのRowDefinitionsを設定します
- C1FlexGridを貼り付けます
- C1FlexGridのプロパティを設定します
- C1FlexGridの下にButtonを貼り付けます
- Buttonのプロパティを設定します
以上の操作を行ってViewA
のXAMLを次のようにします。
FlexGrid本体:
FlexGridのItemsSource
プロパティにビューモデルのOutline
プロパティを連結し、SelectedItem
プロパティにはSelectedProduct
プロパティを連結しています。この設定により、モデルのデータがFlexGridにデータ連結され、FlexGrid上のアクティブ行が移動するたびにその行の情報がビューモデルに伝えられます。
FlexGridの列:
FlexGridの第1列から第3列に対応するデータのフィールド名を設定してデータ連結を可能にします。
Button:
Button
のCommand
にはShowDetailCommand
をバインドします。これによって、ボタンをクリックしたときに明細画面がポップアップされます。
ビューモデル(ViewAViewModel)の作成
ViewModels
フォルダ内のViewAViewModel.cs
に次のように記述します。
ViewAのビューモデルに実装する機能は、次のとおりです。
- コンテナを経由したデータ(DataSet)の取得
- データを保持するDataTable型のOutlineプロパティ
- FlexGridのアクティブ行をビューと共有するSelectedProductプロパティ
- 明細画面をポップアップするShowDetailCommandとShowDetailメソッド
- 明細画面との通信を行うShowDetailRequest(InteractionRequestクラス)
ユーザーコントロールの追加
次の手順で、PrismテンプレートのユーザーコントロールをNavigationプロジェクトに追加します。
- Visual Studioのソリューションエクスプローラーで[Navigation]プロジェクトを右クリックする
- コンテキストメニューから[追加]-[新しい項目]を選択する
- 表示されたリストから「Prism UserControl (WPF) 」を選択する
- View名(Detail.xaml)を指定する
- [追加]ボタンをクリックする
ビュー(Detail)の作成
次の手順でViews
フォルダ内のDetail
ビューを変更します。各プロパティの設定内容については、下のXAMLを参照してください。
- UserControlの各プロパティを設定します
- デフォルトで追加されているGrid内のTextBlockを削除します
- GridのRowDefinitionsを設定します
- C1FlexGridを貼り付けます
- C1FlexGridのプロパティを設定します
- C1FlexGridの下にButtonを貼り付けます
- Buttonのプロパティを設定します
以上の操作を行ってDetail
のXAMLを次のようにします。
FlexGrid本体:
FlexGridのItemsSource
プロパティにビューモデルのSales
プロパティを連結しています。これにより、モデルのデータがFlexGridにデータ連結され、親画面のFlexGrid上のアクティブ行に対応した明細情報が表示されます。
FlexGridの列:
FlexGridの第1列から第4列に対応するデータのフィールド名を設定してデータ連結を可能にします。
Button:
Button
のCommand
にはCloseCommand
をバインドします。これによって、ボタンをクリックしたときに明細画面が閉じられます。
ビューモデル(DetailViewModel)の作成
ViewModels
フォルダ内のDetailViewModel.cs
に次のように記述します。
Detailのビューモデルに実装する機能は、次のとおりです。
- コンテナを経由したデータ(DataSet)の取得
- データを保持するDataView型のSalesプロパティ
- 明細画面を閉じるCloseCommandとCloseInteractionメソッド
- 親画面との通信に使う INotificationn型のNotificationプロパティ
- インタラクションの終了処理に使用するAction型のFinishInteractionプロパティ
Module機能の実装
Prismが自動生成するNavigationModule.cs
ファイルを下のように変更します。
RegisterTypesメソッドに追加したコードによって、このModuleがコンテナに登録されてNavigation操作が可能になります。
以上でサンプルアプリケーションの完成です。
作成したサンプルはこちらで公開しています。FlexGrid for WPF(ComponentOne 2019J v2)で作成されています。NuGetパッケージを復元して実行してください。
5. おわりに
製品Webサイトでは、ComponentOne for WPFのデモアプリケーションを公開しています。FlexGrid for WPFをはじめとする数多くのコントロールとライブラリが用意されていますので、以下より是非お試しください。