Prismには、Moduleと呼ばれる機能があります。これはアプリケーションを複数の機能に分割して開発するための仕組みです。Prismでは最終的にModuleに分割したアプリケーションをまとめ上げる機能があります。
ここでは簡単なModuleの使い方を示します。まず、Moduleを作るにはクラスライブラリプロジェクトを作成します。WPFのクラス群が最初から使えるようにカスタムコントロールかユーザコントロール用のライブラリを作成するのが手間が少なくていいです。クラスライブラリを作成したら、初期状態で作成されているクラスを削除してPrism.CoreとPrism.UnityをNuGetから追加します。 そして、Prism.Modularity.IModuleインターフェースを実装したクラスを作成します。このクラスがPrismのモジュールのエントリポイントになります。
作成したModuleは、Bootstrapperクラスのあるプロジェクトにプロジェクト参照を追加して、ConfigureModuleCatalogメソッドをオーバーライドして以下のようなコードでPrismにModuleがあることを伝えます。
protected override void ConfigureModuleCatalog()
{
base.ConfigureModuleCatalog();
var catalog = (ModuleCatalog)this.ModuleCatalog;
catalog.AddModule(typeof(HelloWorldModule.HelloWorldModule));
}
ここでは、HelloWorldModule.HelloWorldModuleクラスがIModuleを実装したクラスになります。
IModuleインターフェースは、Initializeメソッドを持つだけのシンプルなインターフェースです。ここでModuleの初期化処理を行います。
Moduleを作成した具体的なコードの前にRegionについて触れておきたいと思います。PrismはModuleを組み立てることで柔軟にアプリケーションを構築できます。 Module間は疎結合に作られるのが理想的で、Module内のクラスは、何かしらのメッセージング機構を使って連携するのが理想的です。(Prismには、メッセージング機構も用意されています)
柔軟にModuleを組み合わせてアプリケーションを作るための画面側の仕組みとしてRegionというものがあります。れは、Shellをいくつかの区画(Region)にわけて、そこに対して画面部品を流し込むことで画面側も複数Moduleで構成されたときにも柔軟に対応できるようにしています。
Regionを使うには、画面の区画として扱いたいところにRegionNameを付けます。
xmlns:prism="http://prismlibrary.com/"
<ContentControl prism:RegionManager.RegionName="MainRegion" />
RegionNameをつけれるコントロールは、ContentControlのほかにItemsControl(を継承したコントロール)があります。 ContentControlは、Region内でアクティブになれるViewが1度に1つなのに対して、ItemsControlは複数のViewに対応している点が異なります。
このようにRegionを作成したら、Prismの提供するIRegionManagerのRequestNavigateを呼び出すことでViewを表示できます。
this.RegionManager.RequestNavigate("MainRegion", nameof(HelloWorldView));
ということで、ModuleとRegionを使った簡単なプログラムを組んでいきたいと思います。ModuleAppという名前でWPFアプリケーションを作成して、Prism.CoreとPrism.UnityをNuGetから追加します。 そして、Shell.xamlを作成してBootstrapperクラスを作成して、表示するところまで作成します。
ModuleApp.HelloWorldModuleという名前でWPF カスタムコントロール ライブラリを作成して、カスタムコントロールのコードを削除します。そこにPrism.CoreとPrism.UnityをNuGetから追加します。 ここに各種クラスを作っていきます。
こんにちは世界と表示するViewを作成します。まず、Models名前空間に以下のようなメッセージを提供するクラスを作成します。
namespace ModuleApp.HelloWorldModule.Models
{
class MessageProvider
{
public string Message { get; } = "こんにちは世界";
}
}
そして、HelloWorldViewModelクラスを作成します。先ほどのMessageProviderをインジェクションするようにしています。
using Microsoft.Practices.Unity;
using ModuleApp.HelloWorldModule.Models;
namespace ModuleApp.HelloWorldModule.ViewModels
{
class HelloWorldViewModel
{
[Dependency]
public MessageProvider MessageProvider { get; set; }
}
}
最後に、HelloWorldViewを作成します。Views生空間にユーザーコントロールを作成して、XAMLを以下のように編集します。
<UserControl x:Class="ModuleApp.HelloWorldModule.Views.HelloWorldView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ModuleApp.HelloWorldModule.Views"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBlock Text="{Binding MessageProvider.Message}" />
</Grid>
</UserControl>
prism名前空間の追加とViewModelLocatorの追加をして、先ほど作成したHelloWorldViewModelがDataContextに設定されるようにしています。 そして、TextBlockにMessageProviderのMessageを表示するようにしています。
IModuleインターフェースを実装したクラスを作成します。HelloWorldModuleという名前のクラスをプロジェクト直下に作成します。 HelloWorldModuleクラスのInitializeメソッドでModuleで使用するクラスをIUnityContainerに登録したり、画面をRegionに表示したりといった処理を行います。
using Microsoft.Practices.Unity;
using ModuleApp.HelloWorldModule.Models;
using ModuleApp.HelloWorldModule.Views;
using Prism.Modularity;
using Prism.Regions;
namespace ModuleApp.HelloWorldModule
{
public class HelloWorldModule : IModule
{
[Dependency]
public IUnityContainer Container { get; set; }
[Dependency]
public IRegionManager RegionManager { get; set; }
public void Initialize()
{
this.Container.RegisterType<MessageProvider>(new ContainerControlledLifetimeManager());
this.Container.RegisterType<object, HelloWorldView>(nameof(HelloWorldView));
this.RegionManager.RequestNavigate("MainRegion", nameof(HelloWorldView));
}
}
}
IUnityContainerとIRegionManagerを、PrismからインジェクションしてもらうためにDependency属性をつけたプロパティとして定義しています。 そして、InitializeメソッドでRegisterTypeをして必要なクラスを登録しています。
注意点としては、Viewの登録は必ずobject型として登録する必要がある点です。また名前は型名で登録するのが一般的です。
最後にRegionManagerのRequestNavigateメソッドで、Shellに定義されたMainRegionにHelloWorldView(上でUnityに登録しているやつ)を流し込んでいます。
ここまでで、プロジェクトは大体こんな形になっています。
- ModuleApp
- Views
- Shell.xaml
- Bootstrapper.cs
- Views
- ModuleApp.HelloWorldModule
- Models
- MessageProvider.cs
- ViewModels
- HelloWorldViewModel.cs
- Views
- HelloWorldView.xaml
- HelloWorldModule.cs
- Models
最後に、Moduleを組み込むコードをBootstrapperに追加します。Moduleの構成は、BootstrapperのConfigureModuleCatalogメソッドで行います。 ここでModuleCatalog(IModuleCatalog型)をModuleCatalog型にキャストして、AddModuleで先ほど作成したHelloWorldModuleを追加します。
using Microsoft.Practices.Unity;
using ModuleApp.Views;
using Prism.Modularity;
using Prism.Unity;
using System.Windows;
namespace ModuleApp
{
class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
return this.Container.Resolve<Shell>();
}
protected override void InitializeShell()
{
((Window)this.Shell).Show();
}
protected override void ConfigureModuleCatalog()
{
base.ConfigureModuleCatalog();
var catalog = (ModuleCatalog)this.ModuleCatalog;
catalog.AddModule(typeof(HelloWorldModule.HelloWorldModule));
}
}
}
実行すると、ModuleがShellにHelloWorldModuleで定義されたHelloWorldViewが表示されて、画面にこんにちは世界と表示されることが確認できます。