Prism UI 合成 QuickStart
http://msdn.microsoft.com/en-us/library/ff921174(v=pandp.40)
ビジネスシナリオ
UI 合成 の サンプルは、架空のリソース管理システムに基づいています。メインウィンドウは、さらに大きなシステムのサブセットを表現しています。このウィンドウで、ユーザーは、従業員についての詳細な情報を確認することができ、連絡先を更新することができます。
ビルドと実行
- Silverlight only – Open QS – UI Composition QuickStart.bat を実行するとソリューションが起動する
- UIComposition.Web プロジェクトを右クリックし、スタートアッププロジェクトに設定を選択
- F5 で実行
ウォークスルー
1.メインウィンドウには、従業員のリストが表示されている
2.従業員の名前をクリックすると、動的に View がロードされ、詳細が表示される
3.他のタブを表示すると、追加の情報が表示される
実装について
このサンプルで重要なのは、Region の利用と、View を発見し、注入する方法
- Shell Vew : アプリケーションのメインウィンドウ。Left および Main Region を含んでいる
- Left Region : このRegion は、View を見つけ出し、業員リストViewを含む
- Employees List View : 従業員リスト
- Main Region : 従業員サマリーView(Employees Summary View) を注入する
- Employees Summary View : 従業員のタブ Region に従業員情報を View注入を行い、表示する
- Tab Region : 従業員サマリーView(Employees Summary View) の中にあり、従業員詳細(Employee Details) および プロジェクト(Employee Project) View を持つ
- Employee Detals View : 選択された従業員の詳細を表示
- Employees Project View : 従業員が従事しているプロジェクトリストを表示
UI の組み立て
サンプルでは、View の発見とViewの注入を行っている
XAML で Region を設定する
- Shell は ShellView.xaml にて、LeftRegion、MainRegion の2つの Region を定義する
- EmployeeSummaryView.xamlにて、EmployeeSummaryView は、Tab コントロールを含み、TabRegion を 定義している
- EmployeeSummaryView.xmalにて、TabRegion は、選択された従業員への参照を提供する、RegionContext を定義している
View の表示
- App.xaml.cs の Application_Startup メソッドは、Bootstrapper を生成し、起動する
- Bootstrapper の CreateModuleCatarog メソッドで、モジュールカタログが設定からロードされる。このモジュールカタログは、ModuleInit クラスに実装された EployeeModule のみを定義しており、起動後、直ちにPrismによりロードされる
- EmployeeModule で、ModuleInit クラスのInitialize メソッドがBootstrapper から呼び出される。このメソッドは、さまざまなことを行う。
- IEmployeeDataService の登録
- MainRegionController の生成
- ラムダ式を利用し、EmployeeListView を LeftRegion に登録
- EmployeeDetailView および EmployeeProjectsView を TabRegion に登録
- その後、Bootstrapper の CreateShell メソッドが呼び出され、LeftRegionおよびMainRegion を含む、ShellView のインスタンスが生成される
- LeftRegion の生成にて、Prism は、LeftRegion に登録されたラムダ式によりインスタンス化されたEmployeeListView をアクティブ化し表示する
- MainRegion には、View が登録されていないので、なにも表示されない
EmployeeListView で従業員が選択されると
- MainRegionController の EmployeeSelected メソッドが EmployeeSelectedEvent を購読していることにより、EventAggreagator を通して呼び出される。このイベントは、EmployeeListViewModel クラスのSelectedEmployeeChanged メソッドから発行される。
EmployeeSelected メソッドで実行されること
- 選択された従業員が、EmployeeDataService から参照される
- MainRegion がRegionManager から参照され、メソッドは、EmployeeSummaryView という名前のViewを見つけようとする。というのは、このViewはまだ生成されておらず、コンテナからインスタンスが参照され、明示的にViewがMainRegion に注入される。
- EmployeeSummaryView が生成されるとき、TabRegion も生成される。TabRegion は、RegionContext を保持しており、CurrentEmployee に結びつけられる(EmployeeSummary.xaml) このとき、以下のことが起こる。
- Prism は、TabRegion が複数のViewを持っており、EmployeeDetailsView および EmployeeProjectsView のインスタンスを生成し、表示すべきであることを決定する。それぞれのView は、RegionContext の PropertyChange イベントを購読している
- RegionContext のバインドが更新されると、PropertyChanged イベントがトリガーされる
- EmployeeDetailsView および EmployeeProjectsView は RegionContext プロパティが変更された通気を受け、結びつけられた View Model は更新されるため、選択された従業員が表示される
View の発見と注入の適用
View を発見する手法では、モジュールでコレクションに格納されたペア(View型とRegion名) にもとづいて登録された、 Regionの内側にViewを引き込む。この登録は、RegionViewRegistory という名前。Region が生成されるとき、RegionViewRegistory は、Region名に結びつけられたすべてのView型を探しだす。一致するViewが生成され、Regionに引き込む。この手法を利用するとき、Region インスタンスは、生成し注入するViewを探すための名前を明示的には保持しない。
一般的に、他のViewにホストされるViewは、子Viewで利用できるようにコンテキストを保持する。サンプルでは、動的に子Viewをロードしたときに、従業員の詳細を表示するために、どの従業員が現在選択されているかを知る必要がある。
Viewの注入手法は、View を すでに存在している Region の押し込むことを許可する。これは、Viewのインスタンスを生成することを要求し、Region への参照を取得し、それぞれを Region の Add メソッドを使ってRegionViewRegisory で結びつける。
View 発見手法とView注入手法
- View 発見モデルには、タイミングの問題がない。例えば、あるモジュールがViewをRegionに追加することを試みる場合に、生成されていないということがない。
- 同じRegionの複数のインスタンスを表示するのが簡単。なぜなら、特定Regionのインスタンスを見つけ、Viewに注入するための のスコープ管理について知る必要がないため。
- RegionViewRegistory クラスに、GetContents メソッドを利用して、特定のRegionに結びつけられたすべてのViewを取得する問い合わせを投げることができる。例えば、このリストは、メニューに対応付けられる。
- Viewの発見と合成において、Regionは、Visual Treeに追加されるとすぐに配置される。なので、ViewがRegion に追加されたら、制御しにくい。もし、View を狙った時にロードしたい場合、Viewの発見手法では困難。
- サンプルでは、DetailRegion Regionは、EmployeeDetails View を取得し押し込む。View注入モデルは、ここでは、スコープ付きRegionの利用法を見せるために使われている。従業員を選択したとき、新しい EmployeeDetailsView が生成され、必要なら、EmployeeController により、DetailRegion Regionに押し込まれる。
- View の発見と合成は、Regionが同時に同じViewの複数のインスタンスを持つ場合など、スコープ付きRegion Manager が必要な場合は使用すべきでない。なぜなら、Region は、Region Manager から、一意な名前で登録されているViewを取得するため。
- サンプルでは、リストから従業員が選択された時に、いくつかのEmployeeDetailsView のインスタンスが生成され、メモリに保持される。それぞれのViewは、独自に TabRegion をもっているため、Viewhaそれぞれ独自の Region Manager を必要とする。
- あたらしい TabRegion が生成されるとき、Project モジュールに登録された、ProjectsListView の新しいインスタンスも引き出され、表示される。
View の登録
Prism ライブラリのRegionViewRegisotry クラスは、Region名、View型ペアの登録および参照に責任を持つ。一般的に、アプリケーションモジュールは、自分の View をRegionViewRegistory インスタンスを利用して、 Initialize メソッドで登録する。
EmployeeListView と LeftRegion を EmployeeModule モジュールの ModuleInit クラスの Initialize メソッドで登録する例。
this.regionManager.RegisterViewWithRegion( RegionNames.LeftRegion, () => this.container.Resolve());
Prism ライブラリ のRegionViewRegistry クラスの RegisterViewWithRegion メソッドは、Region名とViewを結びつけて登録するのに利用される。このメソッドを利用するには2つの方法がある。
- RegionViewRegistory を直接利用する
- RegionManager インスタンスを利用する(簡単にRegionViewRegistoryクラスにアクセスできる様に拡張メソッドが用意されている)
RegionManager の拡張メソッドは簡単にアクセスするために存在しており、View と Region Manager のインスタンスを登録することはできない。Regionを特定の名前で生成した場合は、Scope付き Region Managerかに関わらず登録され、View はそこに差し込まれる。
RegisterViewWithRegion メソッドは、2つのオーバーロードを持っている
- RegisterViewWithRegion(string regionName, Type viewType);
- RegisterViewWithRegion(string regionName, Func<object> getContentDelegete);
Viewを直接登録したい場合、最初のオーバーロードを利用する。”presenter first” または、”ViewModel-first” アプローチにおいて、Viewの生成に責任を持つプレゼンターを解決するデリゲートをInitializeメソッドで提供したい場合などは、2つめのオーバーロードを利用する。
最初のオーバーロードを使用した場合は、Region が生成されたとき、結びつけられたView を登録された中から探す。一致したViewが引っ張り出され、Regionの中にロードされる。新しいViewのインスタンスは、Service Locator を使って生成される。
View 間で Context を共有する
プロパティが接続されたRegionContext は、context を 親View と親Viewがホストする子Viewとで共有したい場合、便利である。この接続されたプロパティは、シンプルか複雑かに関わらずオブジェクトを保持できる。
UI 合成のサンプルにおいて、RegionContext は、選択された従業員IDを ProjectListView に受け渡し、Viewに、従業員が従事しているプロジェクトを表示するのに利用される。
EmployeeSummaryView.xmal ファイルでの例
<sdk:TabControl Grid.Row="1" AutomationProperties.AutomationId="EmployeeSummaryTabControl" Margin="8" prism:RegionManager.RegionName="TabRegion" prism:RegionManager.RegionContext="{Binding CurrentEmployee}" Width="Auto" Height="Auto" HorizontalAlignment="Stretch"> </sdk:TabControl>
Viewで、RegionContext を取得するために、GetObservableContext スタティックメソッドが RegionContext クラスで使われる。これは、Viewにパラメータを渡し、Value プロパティにアクセスすることができる。
EmployeeDetailsView.xaml.cs
employeeDetailsViewModel.CurrentEmployee = RegionContext.GetObservableContext(this).Value as Employee;
RegionContext の値は、新しい値を Value プロパティに設定することで簡単に変更できる。RegionContext プロパティが変更されたことも、イベントを購読することで検知できる。
EmployeeDetailsView.xmal.cs
RegionContext.GetObservableContext(this).PropertyChanged += (s, e) => employeeDetailsViewModel.CurrentEmployee = RegionContext.GetObservableContext(this).Value as Employee;
DataContext プロパティは、Context の共有に利用できない。なぜなら、DataContext プロパティは、一般的に、View に対する、View Model を保持するのに利用されるため。