Home > C# > Toolkit > UIパターン > Prism > Prismドキュメント > Prism 6

Prism Library 5.0 for WPFを拡張する

新規作成日 2017-11-27
最終更新日

原文「Extending the Prism Library 5.0 for WPF

Prismには、Windows Presentation Foundation (WPF)クライアント開発のための推奨された実践を表示する資産が含まれています。開発者は、Model-View-ViewModel(MVVM)パターンを使用して、複合アプリケーションを作成する、ガイダンスの変更されていないバージョンを使用できます。しかしながら、各々のアプリケーションが、一意であるため、あなたは、あなたの個々の必要性のために、Prismが、適切か分析する必要があります。場合によっては、あなたは、あなたの企業に、最も良い実行を組み込むために、ガイダンスをカスタマイズしたいと思うでしょう。そして、頻繁に開発者の作業を繰り返します。

Prismライブラリは、あなたのWPFクライアント・アプリケーションのために、基盤の役割を果たします。Prism Libraryは、特定のシナリオに合わせて、重要な部分をカスタマイズまたは置き換えることができるように設計されました。あなたは、新しい機能を組み込むために、既存のライブラリのためのソース・コードを変更することができます。構造の中に、重要なコンポーネントを配置して、構築するコンテナに依存するため、開発者は、独自のデザインで、アーキテクチャ内の重要なコンポーネントを置き換えることができます。ライブラリでは、あなたが望む場合、あなたは、コンテナそのものでさえ、置き換えることさえできます。カスタマイズするための他の共通の領域は、あなた独自のコンテナと作成するあなた独自の領域アダプタを使用して、あなた独自のロガーを呼び出して、モジュールを読み込むためのモジュール発見戦略を選択するために、ブートストラッパーを作成、あるいは、カスタマイズすることが含まれています。

このトピックは、Prism Library内のいくつかの重要な拡張ポイントを説明します。これらは、より高等なトピックである傾向があり、ほとんどの開発者が、Prism Libraryを使用して、実行することは、期待していません。Prism Libraryの目標と設計決定を確実に理解することは、副作用の作成、あるいは、アーキテクチャを低下させない、Prismの機能に拡張を確実に行うために、役立ちます。Prismのドキュメンテーションの主なトピックは、Prism Libraryを拡張する前に、読むことを推奨します。この文書で説明される技術のほとんどは、アプリケーションを起動するとき、ブートストラップ・シーケンスの間に、Prism Libraryのデフォルトコンフィグレーションを置き換える、あるいは、変更することに依存しているため、セクションを中で読み込むことは、前提条件です。

以下は、このトピックで取り扱われる、Prism Libraryの重要な拡張ポイントです。:

  • アプリケーションのBootstrapper。Application Bootstrapper.これは、Prism Libraryの重要な拡張ポイントを説明します。
  • モジュール方式。Modularity.モジュール・アプリケーションを構築するとき、これは拡張ポイントを説明します。
  • 領域管理。Region Management.この拡張は、どのように、領域が動作するか、それらが、どのように、格納されるか、そして、それらが、それらのViewと、どのように相互作用するか、説明します。
  • 領域ナビゲーション。Region Navigation.これは、あなたの論理ナビゲーション構造を、どのように変更するか説明します。
  • ViewModelロケーター。View Model Locator.これは、View Modelロケーターを使用している時、規則を、どのように変更するかを説明します。

拡張性のためのガイドライン

Guidelines for Extensibility

あなたが、Prism Libraryを拡張するとき、これらのガイドラインを使用します。あなたは、追加する、あるいは、サービスを置き換える、ソース・コードを変更する、あるいは、新しいアプリケーション機能を追加することで、ライブラリを拡張できます。

機能を公開する

Exposing Functionality

ライブラリは、その機能を公開するために、public APIを与える必要があります。APIのインターフェイスは、内部実装から独立している必要があります。開発者は、その既定の機能を効果的に使用するために、ライブラリの設計や実装を理解することを、求められていません。可能な限り、APIは、固有の機能のための共通のシナリオを適用する必要があります。

ライブラリを拡張する

Extending Libraries

Prismライブラリは、開発者は、それらのニーズに合わせて、ライブラリを調整するために、使用することができる、拡張ポイントを提供します。例えば、Prism Libraryを使用すると、あなたは、与えられたログの記録サービスを、あなた独自のログの記録サービスに置き換えることができます。

あなたは、そのソース・コードを変更することなく、ライブラリを拡張できます。これを達成するために、あなたは、public基底クラスやインターフェイスのような、拡張ポイントを使用する必要があります。開発者は、基底クラスを拡張することができる、あるいは、インターフェイスを実装することができ、そして、ライブラリに、それらの拡張を追加します。拡張ポイントの設定を定義するとき、ユーザビリティ上で効果を考慮します。拡張ポイントの多くは、使用するために、そして、設定することが難しい、複雑なライブラリを作成することができます。

一部の開発者は、拡張ポイントを使用して、ソース・コードを変更することを示す、コードをカスタマイズすることに、興味を持っている可能性があります。この努力に対応するために、ライブラリ・デザインは、次のことを提供する必要があります。:

  • 実際的な場合はいつでも、オブジェクト指向デザインの原則に従う必要があります。
  • 実際的な場合はいつでも、オブジェクト指向デザインの原則に従う必要があります。
  • それは、リソースを効率的に使用する必要があります。
  • それは、セキュリティの原則を厳守する必要があります。(たとえば、ユーザー入力を疑う、そして、最小特権の原則)。

Prism Libraryを変更するための推奨事項

Recommendations for Modifying the Prism Library

ソース・コードを変更するとき、これらのベスト・プラクティスに従ってください。:

  • ライブラリが、そのデザインを説明するトピックを読み込むことによって、どのように動作するかについて理解してください。あなたが、コードを大幅に変更する場合、あるいは、あなたが、オリジナル・バージョンと一緒に、ライブラリのあなたがカスタマイズしたバージョンを使用したい場合、ライブラリの名前空間を変更することについて、考えてみてください。
  • あなた独自のアセンブリを作成することについて考えると、Prism Libraryバイナリを変更したり、置き換える前に、まず、Prism Libraryに組み込まれた拡張ポイント使用します。
  • 厳密な名前を使用する。厳密な名前は、アセンブリ、バージョン、整合性の確認を一意に識別できます。あなたは、アプリケーション・ブロックの変更されたバージョンに署名するために、あなた独自の鍵の対を作成する必要があります。詳細については、MSDNの厳密な名前のアセンブリを参照してください。他の方法として、あなたは、あなたのカスタム・バージョンに署名しないことを選択することができます。これは、弱い命名として参照されます。

Prism Libraryの拡張ポイント

Extensibility Points in the Prism Library

この項目は、機能分野によって、そして、ライブラリを拡張するための関連する情報の拡張ポイントを概要を述べます。

コンテナとBootstrapper

Container and Bootstrapper

Prism Libraryは、直接、依存関係注入コンテナとして、Unityアプリケーション・ブロック(Unity)と拡張管理フレームワーク(MEF)をサポートしています。;しかしながら、コンテナが、IServiceLocatorインターフェイスによって呼び出されるため、コンテナは、置き換えることができます。

各々のPrismアプリケーションは、ブートストラッパー・クラスによってPrism Libraryを設定します。ブートストラップ工程の各段階は、工程そのものと同様に、交換可能です。ブートストラッパーは、デフォルトの実装をカスタム実装で、あるいは、追加のデータ型とサービスを登録する、交換をするために、重要な拡張ポイントを提供します。

ログの記録

Logging

Prism Libraryは、直接、依存関係注入コンテナとして、Unityアプリケーション・ブロック(Unity)と拡張管理フレームワーク(MEF)をサポートしています。;しかしながら、コンテナが、IServiceLocatorインターフェイスによって呼び出されるため、コンテナは、置き換えることができます。

各々のPrismアプリケーションは、ブートストラッパー・クラスによってPrism Libraryを設定します。ブートストラップ工程の各段階は、工程そのものと同様に、交換可能です。ブートストラッパーは、デフォルトの実装をカスタム実装で、あるいは、追加のデータ型とサービスを登録する、交換をするために、重要な拡張ポイントを提供します。

モジュール。

Modules

Prism Libraryは、モジュール・カタログを埋め込むさまざまな方法とロードモジュールを提供します。;しかしながら、あなたのシナリオは、ライブラリを与えない必要があるかもしれません。

モジュールの読み込みは、カスタマイズすることができる、次の3つの段階が含まれています。:

  • モジュール発見。

    Module discovery.

    これは、モジュール・カタログを埋め込む工程です。頻繁に、これは、直接、あるいは、ディレクトリを掃引して行われますが、あなたのアプリケーションは、これを、データベースのような、他の方法で行う必要があるかもしれません。これらの場合では、あなたは、適切なソースからそれ自体を埋め込む、カスタム・カタログを作成することができます。

  • モジュールの検索と読み込み。

    Module retrieval and loading.

    これは、ローカルに、モジュール・バイナリを取得する工程です。そして、現在のアプリケーション・ドメインに、モジュールを読み込みます。ライブラリは、FileModuleTypeLoaderを提供しますが、あなた独自の探索戦略を実装することもできます。

  • モジュールの初期化。

    Module initialization.

    これは、モジュールを初期化する処理です。ライブラリでは、これは、ModuleInitializerによって行われますが、ModuleInitialzerを実装する、新しいオブジェクトを提供することで、置き換えることができます。

Region

Regions

Prismライブラリは、領域として、コントロールを可能にするために、既定のコントロール・アダプタを提供します。領域の周りの拡張は、カスタム領域アダプタ、カスタム領域を与える、あるいは、領域マネージャーを置き換えることを必要とするかもしれません。 あなたが、それは、与えられた領域アダプタでは、動作しない、カスタムWPFコントロールやサードパーティ製のコントロールを持っている場合、あなたは、カスタム領域アダプタを作成するといいかもしれません。また、それは、コンテナに、新しいIRegionManagerを提供することによって、既定のRegionManagerを置き換えることができます。

領域ナビゲーション。

Region Navigation

Prismライブラリは、領域として、コントロールを可能にするために、既定のコントロール・アダプタを提供します。領域の周りの拡張は、カスタム領域アダプタ、カスタム領域を与える、あるいは、領域マネージャーを置き換えることを必要とするかもしれません。 あなたが、それは、与えられた領域アダプタでは、動作しない、カスタムWPFコントロールやサードパーティ製のコントロールを持っている場合、あなたは、カスタム領域アダプタを作成するといいかもしれません。また、それは、コンテナに、新しいIRegionManagerを提供することによって、既定のRegionManagerを置き換えることができます。

領域ナビゲーション。

Region Navigation

また、Prism Libraryの領域機能は、戻る/進むの更新履歴サポートが含まれているナビゲーションをサポートしています。領域の中のViewは、INavigationAwareインターフェイスを通して、ナビゲーション内で、拡張、そして、関与することができます。Silverlightナビゲーション機能に精通している開発者は、Frameクラスに類似した領域を見つけるでしょう。領域ナビゲーションは、ナビゲーション・サービスの置き換えに加えて、アプリケーションの論理的なナビゲーション構造を変更することを可能にするいくつかの拡張ポイントをサポートしています。

RegionNavigationContentLoaderクラスは、NavigationContextに基づいた領域に、内容を読み込む能力を提供します。移動される内容が、すでに領域内にある場合、RegionNavigationContentLoaderは、その内容を配置します。そして、領域を追加するための新しい内容を作成する代わりに、それをアクティブとして作成します。RegionNavigationContentLoader.GetCandidatesFromRegionメソッドは、型で、それらと一致している領域Viewを検索します。しかしながら、それは、Viewが、解決するために使用される型と一致しない型を持つことは、可能です。 例えば、あなたは、あなたのView型の名前と一致しない「親しみやすい」名前を使用して、依存関係注入コンテナで、Viewを登録することができました。

Prismライブラリは、可能な親しみやすい名前の登録をView型に基づいて見つけるのに、必要な特別な処理を提供する、GetCandidatesFromRegion基底メソッドを上書きするUnityRegionNavigationContentLoaderとMefRegionNavigationContentLoaderを発送します。あなたが、UnityRegionNavigationContentLoaderかMefRegionNavigationContentLoaderを使用していない場合、それで、あなたが使用している依存関係注入コンテナに固有のRegionNavigationContentLoaderのサブクラスに、ハンドリングを追加したことを確認します。

コンテナとBootstrapper

Container and Bootstrapper

Prism Libraryには、Bootstrapper基底クラスが含まれています。UnityとMEFコンポーネントは、それぞれ、UnityBootstrapperとMefBootstrapperとして、このクラスから派生します。Bootstrapper基底クラスは、工程の正確な順序付けを、派生クラスに残す、抽象的なRunメソッドを定義します。ほとんどすべてのメソッドは、カスタマイズ、そして、ブートストラップ工程を拡張するために、それぞれのメソッドを上書できる、仮想であるように、マークされます。

ほとんどの型のインスタンス化のために、ブートストラッパーは、依存関係注入コンテナを使用するでしょう。しかしながら、コンテナを使用することができない、ブートストラップ工程のいくつかの部分があります。:

  • ロガーを作成する

    Creating the logger.

    通常、ブートストラッパーは、コンテナを作成することに関する情報を記録する必要があるため、ロガーは、まず、(コンテナの前に)作成されます。ログの記録の実装を変更することの詳細については、「ログの記録」の項目を参照してください。

  • カタログを作成して、設定する

    Creating and configuring catalogs.

    カタログ(たとえば、ModuleCatalogとAggregateCatalog)は、コンテナ構築の間、使用されるため、コンテナの前に、作成されます。

  • シェルを作成する

    Creating the shell.

    ブートストラップ・シーケンスを実行する前に、シェルがすでに存在するかもしれないため、CreateShellメソッドは、実装するアプリケーション開発者のため、抽象として、残っています。アプリケーション開発者は、コンテナが作成され、そして、初期化されたため、シェルをインスタンス化、あるいは、配置するために、コンテナを使用することができます。

既定のPrism Library型を置き換える

Replacing Default Prism Library Types

あなたが、アプリケーションのために、Prism Library型の基盤となる実装を変更、あるいは、拡張する必要があるとき、時間があるかもしれません。Prism Libraryが、依存関係注入に依存するため、あなたは、ブートストラップ・シーケンスの間、型を置き換えることができます。そして、あなたのアプリケーションとPrism Libraryは、新しい型を使用するでしょう。

既定のデータ型をUnityを使用して、置き換える

Replacing Default Types Using Unity

どんな置換型でも、コンテナに登録しました。UnityBootstrapper.ConfigureContainerメソッドが、呼び出される前に、型を置き換えるでしょう。関連付けられたインターフェイスが、すでに登録されていない場合、ConfigureContainerデフォルトの実装は、Prism Library型を追加するためだけに、RegisterTypeIfMissingメソッドを使用します。

Prism Library型をUnityに置き換えるために、まず、あなたが、置き換えたい、インターフェイスやクラスから、あなたの新しい型を派生します。次のコード例は、IEventAggregatorインターフェイスの置き換えを示します。

// when using Unity
public class ReplacementEventAggregator : IEventAggregator
{
    // ...
}

今、あなたは、ブートストラッパーで、ConfigureContainerメソッドを上書きする、インターフェイスと型を登録する、基底クラスを呼び出す前に、置き換えた型を持っています。次のコード例は、どのように、IEventAggregatorの置き換えを登録するかを示します。

// when using Unity
protected override void ConfigureContainer()
{
    this.RegisterTypeIfMissing(typeof(IEventAggregator), typeof(ReplacementEventAggregator), true);
    base.ConfigureContainer();
}

既定の型をMEFを使用して、置き換える

Replacing Default Types Using MEF

MefBootstrapper.ConfigureContainerメソッドが、呼び出される前に、どんな置換型でも、コンテナに登録し、型を置き換えるでしょう。関連付けられたインターフェイスが、すでに登録されていない場合、ConfigureContainerの既定の実装は、Prism Library型を一つだけ追加します。

Prism Library型をMEFに置き換えるために、まず、あなたが望むインターフェイスから、適切なMEFエクスポート属性を、それに置き換えて、適用するために、あなたの新しい型を派生します。次のコード例は、IEventAggregatorインターフェイスの置き換えを示します。

// when using MEF
[Export(typeof(IEventAggregator))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class ReplacementEventAggregator : IEventAggregator
{
    // ...
}

今、あなたは、ブートストラッパーで、ConfigureAggregateCatalogメソッドを上書きし、そして、AggregateCatalog型に含まれるカタログを追加する、置き換えた型を持っています。次のコード例は、置換型を追加するために、TypeCatalogを、どのように、使用するかを示しています。また、AssemblyCatalogは、使用することができます。

MEFコンテナに、非MEF属性型を登録する

Registering Non-MEF Attributed Types with the MEF Container

あなたが、コードを所有し、そして、MEF上で、直接、依存関係を取得する場合、あなたは、Export属性を型に追加するだけなので、MEFで型を登録することは、簡単です。しかしながら、いくつかの状況では、あなたが、MEFアセンブリの上で、直接、依存関係を取得できないとき、あなたは、MEFで、型を登録することを必要とするかもしれません。この問題は、MEFサポートをPrismに追加している間に、設計目標の1つを確実とするため、コアPrismライブラリが、コンテナ固有でなかったために、開発者が、直面しました。これは、Microsoft.Practices.Prismアセンブリが参照することができないことを示しています。

System.ComponentModel.CompositionとExport属性を使用する代わりに、チームは、チームが、公開することを望んだ型から派生し、そして、適切な型をエクスポートするMicrosoft.Practices.Prism.MefExtensionsアセンブリに、派生クラスを作成しました。MefRegionManagerクラスから、次のコード例は、RegionManagerから派生し、そして、IRegionManagerとして、新しい型をエクスポートすることで、このアプローチの例を示しています。

[Export(typeof(IRegionManager))]
public class MefRegionManager : RegionManager
{
}

最少のBootstrapperを作成する

Creating a Minimal Bootstrapper

一部のアプリケーションでは、Prism Libraryの機能の多くを使用していません。場合によっては、アプリケーション開発者は、絶対最小のサービス水準を望むかもしれません。-依存関係の注入とサービスの位置だけ。これを実行するには、次に示すブートストラッパーと実装で、ConfigureContainerメソッドを上書きします。

基底クラスの実装は、故意に、base.ConfigureContainer()を呼び出しません。;

// when using UnityBootstrapper
// UnityBootstrapperを使用するとき、
protected override void ConfigureContainer()
{
    // Base class implementation deliberately not called
    // base.ConfigureContainer();
    // 基底クラスの実装は、故意に、base.ConfigureContainer()を呼び出しません。;
    this.Container.AddNewExtension<UnityBootstrapperExtension>();
    Container.RegisterInstance<ILoggerFacade>(Logger);
    this.Container.RegisterInstance(this.ModuleCatalog);
    RegisterTypeIfMissing(typeof(IServiceLocator), typeof(UnityServiceLocatorAdapter), true);
}

protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
{
    return null;
}

protected override IRegionBehaviorFactory ConfigureDefaultRegionBehaviors()
{
    return null;
}

備考: インターフェイスの実装が、要求されるとき、Unityが、返すために、適切で、具体的な型を決定できないため、領域アダプタとマッピングのオーバーライドは、必要とされます。これらは、それぞれのインターフェイスを返すために、具体的な型の関連付けを呼び出します。必要とされる具体的な型が、要求されるとき、Unityは、型をインスタンス化することによって、直接、それらを解決することができます。

// when using MEFBootstrapper
protected override void ConfigureContainer()
{
    // Base class implementation deliberately not called
    // base.ConfigureContainer();
    // 基底クラスの実装は、故意に、base.ConfigureContainer()を呼び出しません。;

    this.Container.ComposeExportedValue<ILoggerFacade>(this.Logger);
    this.Container.ComposeExportedValue<IServiceLocator>(new MefServiceLocatorAdapter(this.Container));
    this.Container.ComposeExportedValue<AggregateCatalog>(this.AggregateCatalog);
}

依存関係注入コンテナを変更する

Changing Dependency Injection Containers

あなたが、あなたのアプリケーションで、UnityやMEF以外のコンテナ付きのPrismを使用する場合、あなたが、行う必要がある、いくつかのことがあります。まず、あなたは、あなたのコンテナのためのサービス・ロケーター・アダプタを記述することを必要とします。あなたは、どのように、行うことができるかの例として、MefServiceLocatorAdapterとUnityServiceLocatorAdapterを使用することができます。また、あなたは、コンテナ固有のブートストラッパー・クラスを記述する必要があります。次に、あなたは、Bootstrapperクラスから派生する、新しいコンテナ固有のブートストラッパーを作成する必要があります。そして、例として、MefBootstrapperとUnityBootstrapperの利用して、必要なメソッドを実装します。

ログの記録

Logging

Prism Libraryは、ライブラリを通して、メッセージをログに記録するように設計されています。この方法で、固有のログの記録ライブラリに拘束されずに、ログを記録するために、Prism Libraryは、そのメッセージを記録するために、ログの記録外見、ILoggerFacade、を使用します。このインターフェイスには、ログ・メッセージを記録する、Logという名前の一つのメソッドが含まれています。既定では、UnityBootstrapperとMefBoostrapperは、指定されたロガーとして、TextLoggerを作成します。

カスタム・ロガーを作成して、統合するための、3つの段階があります。:

  • ILoggerFacadeインターフェイスを実装するクラスを作成します。
  • ログ・メソッドを実装します。
  • あなたのアプリケーション・ブートストラッパー・クラスでは、あなたのログの記録クラスの新しいインスタンスを返すために、CreateLoggerメソッドを上書きします。

ILoggerFacadeインターフェイスのLogメソッドは、3つのパラメータを取得します。:

  • メッセージ。

    Message.

    これは、記録されるメッセージです。

  • 分類

    Category.

    これは、記録されるイベントの分類です。有効なオプションは、Debug、Exception、InfoとWarnです。

  • 優先順位

    Priority.

    これは、記録されるイベントの優先順位です。有効なオプションは、None、High、MediumとLowです。

次のコード例は、文字列だけを取得する、いくつかの他のログの記録フレームワークをラップする、カスタム・ロガーを示します。

// CustomLogger
using Microsoft.Practices.Prism.Logging;
...

public class CustomLogger : ILoggerFacade
{
    public void Log(string message, Category category, Priority priority)
    {
        string messageToLog =
            String.Format(System.Globalization.CultureInfo.InvariantCulture,
                "{1}: {2}. Priority: {3}. Timestamp:{0:u}.",
                DateTime.Now,
                category.ToString().ToUpperInvariant(),
                message,
                priority.ToString());
                MyOtherLoggingFramework.Log(messageToLog);
        }
    }


// ApplicationBootstrapper
using Microsoft.Practices.Prism.Logging;
...

public class ApplicationBootstrapper : UnityBootstrapper
{
    ...
    protected override ILoggerFacade CreateLogger()
    {
        return new CustomLogger();
    }
}

モジュール。

Modules

次の項目は、モジュール方式機能が、登録、アセンブリ発見、型検出とモジュール初期化の間、どのように、拡張されるかを説明します。

機能をModuleカタログに追加する

Adding Features to the Module Catalog

Prismライブラリは、両方のクラスとして、ModuleCatalogを提供します。あなたは、AddModuleメソッドを通して、直接、埋め込むことができます。あるいは、あなたは、Itemsプロパティを埋め込むために、addメソッドから、派生することができます。

Prism LibraryのModuleCatalogクラスは、IModuleインターフェイスを越えた追加機能の多くを提供します。AddModuleメソッド、モジュール・グループの依存関係の検証と並べ替えの多くの異なるオーバーロードがあリます。ModuleCatalogの機能を拡張する、いくつかの方法があります。:

ModuleCatalogから派生します。あなたが、ModuleCatalogの挙動を変更する必要がある場合、新しいクラスを派生し、そして、仮想メソッドを上書きします。

IModuleCatalog上で、拡張メソッドを記述します。あなたが、IModuleCatalogを使用するアプリケーションにおいて、追加の機能を必要とする場合、インターフェイス上で、拡張メソッドを記述します。

ModuleCatalog上で、拡張メソッドを記述します。あなたが、追加の機能を必要とする場合、しかし、あなたが、ModuleCatalogを使用する場所だけで、具体的な型の上で、拡張メソッドを記述します。

カスタム・ソースからモジュールを発見する

Discovering Modules from a Custom Source

Prism Libraryは、アプリケーション設定から、そして、XAMLファイルから、モジュール・カタログを埋め込むことをサポートしています。あなたは、Webサービス、データベース、他の外部ファイルような、他のデータ・ソースからの読み込みをサポートするために、あなたのアプリケーション内で、Prismを拡張できます。

以下は、カタログを埋め込むための、いくつかの方法を説明します。

  • 静的CreateFromXamlメソッドを使用します。あなたのデータが、すでに、Modularity:ModuleCatalog XAMLスキーマである場合、あるいは、それが、簡単に変換することができる場合、あなたは、直接、ModuleCatalogを埋め込む、このメソッドを使用することができます。
  • ConfigurationModuleCatalog内の、IConfigurationStoreを置き換えます。あなたが、WPFデスクトップ・アプリケーションを実行する場合、あなたは、ConfigurationModuleCatalogのためのモジュール項目を返すために、IConfigurationStoreを実装することができます。
  • ModuleCatalogから派生します。また、あなたは、ModuleCatalogから派生するために、あなたのデータを取得する、ConfigurationModuleCatalogの例に従うことができます。そして、その次に、カタログを埋め込むために、AddModuleメソッドを呼び出します。

次のコード例は、ディスクから、カスタム設定モジュール・ファイルを、どのように、読み込むかを示しています。

// Bootstrapper
protected override Microsoft.Practices.Prism.Modularity.IModuleCatalog CreateModuleCatalog()
{
    ConfigurationModuleCatalog catalog = new ConfigurationModuleCatalog();
    catalog.Store = new MyModuleCatalogStore();
    return catalog;
}

// MyModuleCatalogStore
public class MyModuleCatalogStore : IConfigurationStore
{

    public ModulesConfigurationSection RetrieveModuleConfigurationSection()
    {
        ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap()
        {
            ExeConfigFilename = "MyModuleCatalog.config"
        };
        Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
        return configuration.GetSection("modules") as ModulesConfigurationSection;
    }
}

カスタム・アセンブリ・ソースから、モジュールを取得して、読み込む

Retrieving and Loading Modules from a Custom Assembly Source

あなたのアプリケーションが、実装、あるいは、アセンブリ以外の配布の仕組みを持っている場合、あなたは、型をダウンロードあるは呼び出すために、あなた独自のIModuleTypeLoaderを実装することができます。

Prism 4.1ライブラリのMefXapModuleTypeLoaderクラスは、この例です。それは、XAPファイルをダウンロードする、アセンブリを配置する、そして、それらとMEFカタログを登録するために、MEF DeploymentCatalogを使用します。

各々のIModuleTypeLoaderは、モジュールを取得するために使用する、適切な型のローダーを決定するためにModuleManagerを提供する、CanLoadModuleTypeメソッドを実装しています。次のコード例は、MefXapModuleTypeLoader実装**を示しています。**

// MefXapModuleTypeLoader.cs
public bool CanLoadModuleType(ModuleInfo moduleInfo)
{
    if (moduleInfo == null)
    {
        throw new ArgumentNullException("moduleInfo");
    }

    if (!string.IsNullOrEmpty(moduleInfo.Ref))
    {
        Uri uriRef;
        return Uri.TryCreate(moduleInfo.Ref, UriKind.RelativeOrAbsolute, out uriRef);
    }

    return false;
}

あなたが、モジュール・データ型ローダーを持ったあと、あなたは、それが、型ローダーのModuleManagerのコレクションであることを確実にする必要があります。次のコード例は、Prism.MefExtensions.Silverlightプロジェクトからです。

// MefModuleManager.Silverlight.cs
public override IEnumerable<IModuleTypeLoader> ModuleTypeLoaders
{
    get
    {
        if (this.mefTypeLoaders == null)
        {
            this.mefTypeLoaders = new List<IModuleTypeLoader>()
                { this.MefXapModuleTypeLoader }
        }
        return this.mefTypeLoaders;
    }
    set
    {
        this.mefTypeLoaders = value;
    }
}

モジュールの初期化を変更する方法。

Changing How Modules Are Initialized

ModuleManagerから派生します。あなたは、モジュールを読み込みと初期化シーケンスの基本的なビヘイビアを変更する必要がある場合、新しいクラスから派生して、仮想メソッドを上書きします。

**IModuleIntializer**を置き換えます。あなたが、変更する必要がある場合、モジュール型が、インスタンス化、あるいは、初期化される方法を、IModuleIntializer**に置き換えます**。

**カスタムIModuleTypeLoader**を記述します。あなたが、アセンブリが、どのように、読み込まれるか、そして、アセンブリ内の、モジュール型を発見するかを変更する必要がある場合、カスタム**IModuleTypeLoader**を記述します。

詳細については、[カスタムアセンブリソースからのモジュールの取得と読み込み](#検索と読み込みモジュールをカスタムアセンブリソースから取得する)のセクションを参照してください。

Region

Regions

次のセクションでは、領域が、コントロールに添付されるとき、拡張されることができるPrism Libraryの領域管理が、どのように、機能するか、どのように、領域が動作するか、そして、領域が、そのViewをどのように発見するか、を説明します。

領域アダプタ

Region Adapters

領域アダプタは、ホスト・コントロールと相互作用する領域で、項目を、どのように、配置するかを制御します。 次のセクションでは、カスタム領域アダプタとアダプタの登録を制御することを作成することで、このビヘイビアを、どのように、拡張するかを説明します。

ユーザー定義した領域アダプタを作成する

Creating a Custom Region Adapter

領域として、UIコントロールを公開するために、領域アダプタは使用されます。領域アダプタは、領域を作成するための、そして、それをコントロールに関連付けるための、役割を果たします。これを行うことによって、開発者は、IRegionインターフェイスによって、一貫した方法で、UIコントロールの内容を管理することができます。それぞれの領域アダプタは、UIコントロールのそれぞれの型に合わせます。Prismライブラリは、すぐに使える3つの領域アダプタを提供します。:

  • ContentControlRegionAdapter。このアダプタは、System.Windows.Controls.ContentControl型と派生クラスのコントロールに適応させます。
  • SelectorRegionAdapter。このアダプタは、System.Windows.Controls.TabControlコントロールのような、System.Windows.Controls.Primitives.Selectorクラスから派生したコントロールに適応させます。
  • ItemsControlRegionAdapter。このアダプタは、System.Windows.Controls.ItemsControl型と派生クラスのコントロールに適応させます。

前述の領域アダプタのどれでもが、開発者の必要に適切ではない、いくつかのシナリオが、あります。それらの場合において、カスタム領域アダプタは、すぐに使えるPrism Libraryで、サポートされない、コントロールに適応させために作成することができます。

領域アダプタは、Microsoft.Practices.Prism.Regions.IRegionAdapterインターフェイスを実装します。このインターフェイスは、オブジェクトを適応させて、適応するコントロールに関連する新しい領域を返す、Initializeという名前の、一つのメソッドを定義します。それは、インタフェース定義は、次のコードで示されます。

public interface IRegionAdapter
{
    IRegion Initialize(object regionTarget, string regionName);
}

領域アダプタを作成するために、あなたは、RegionAdapterBaseから、あなたのクラスを派生し、CreateRegionとAdaptメソッドを実装します。必要に応じて、領域ビヘイビアをカスタマイズするために、特別なロジックを添付するために、AttachBehaviorsメソッドを上書きします。あなたが、領域を格納するコントロールと相互作用したい場合、また、あなたは、IHostAwareRegionBehaviorを実装する必要があります。

CreateRegionメソッドは、RegionAdapterBaseクラスで定義される抽象メソッドです。それは、適応するコントロールに関連付けるために、(オブジェクトが、IRegionインターフェイスを実装する)領域インスタンスを返します。Prism Libraryは、すぐに使える、次の領域の実装を提供します。:

  • Regions.この領域は、複数のアクティブViewを提供します。これは、Selectorクラスから派生したコントロールのために、使用される領域です。
  • SingleActiveRegion。この領域は、一度に、最大1つのアクティブ・ビューを提供します。これは、ContentControlコントロールのために、使用される領域です。
  • AllActiveRegion。この領域は、その中の、すべてのViewをアクティブに保ちます。Viewの無効化が許可されていません。これは、ItemsControlコントロールのために、使用される領域です。

また、Adaptメソッドは、RegionAdapterBaseクラスで定義される抽象メソッドです。それは、以前に作成された領域に適応します。Adaptメソッドは、2つのパラメータを取ります。:コントロールが適応する領域は、関連付けられ、コントロールに適応します。次のコード例は、ContentControlRegionAdapterを示します。

public class ContentControlRegionAdapter : RegionAdapterBase<ContentControl>
{
    public ContentControlRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory)
        : base(regionBehaviorFactory)
    {
    }

    protected override void Adapt(IRegion region, ContentControl regionTarget)
    {
        if (regionTarget == null) throw new ArgumentNullException("regionTarget");
        bool contentIsSet = regionTarget.Content != null;
        contentIsSet = contentIsSet || (BindingOperations.GetBinding(regionTarget, ContentControl.ContentProperty) != null);

        if (contentIsSet)
        {
            throw new InvalidOperationException(Resources.ContentControlHasContentException);
        }

        region.ActiveViews.CollectionChanged += delegate
        {
            regionTarget.Content = region.ActiveViews.FirstOrDefault();
        };

        region.Views.CollectionChanged +=
            (sender, e) =>
            {
                if (e.Action == NotifyCollectionChangedAction.Add && region.ActiveViews.Count() == 0)
                {
                    region.Activate(e.NewItems\[0\]);
                }
            };
    }

    protected override IRegion CreateRegion()
    {
            return new SingleActiveRegion();
    }
}

備考: 領域アダプタは、シングルトン・サービスとして登録されます。そして、アプリケーションの寿命を通して生きた状態で保たれます。それで、あなたが、おそらく、UIコントロールや領域インスタンスのような、短い生きているオブジェクトの参照を維持していないことを確認してください。

正しい領域アダプタを関連付ける、領域マネージャー・サービスで、XAMLが定義する領域のための、領域アダプタ・マッピングが、使用されています。次の項目は、領域アダプタ・マッピングの登録を、どのように、カスタマイズするかを説明します。

領域アダプタ・マッピングをカスタマイズする

Customizing the Region Adapter Mappings

起動するプロセスの1つの段階は、既定の領域のアダプタ・マッピングを登録することになっています。これらのマッピングが、正しいアダプタを関連付けるために、XAMLが定義する領域のための領域マネージャーで、使用されています。既定では、ItemsControlRegionAdapter、ContentControlRegionAdapterとSelectorRegionAdapterが、登録されます。これらのアダプターの詳細については、以下を確認して下さい。

次のコード例は、ConfigureRegionAdapterMappingsメソッドの既定の実装を示します。領域アダプタの登録をカスタマイズするために、あなたのアプリケーションのブートストラッパーで、このメソッドを上書きします。

// Bootstrapper.cs
protected virtual RegionAdapterMappings ConfigureRegionAdapterMappings()
{
    RegionAdapterMappings regionAdapterMappings = ServiceLocator.Current.GetInstance<RegionAdapterMappings>();
    if (regionAdapterMappings != null)
    {
        regionAdapterMappings.RegisterMapping(typeof(Selector), ServiceLocator.Current.GetInstance<SelectorRegionAdapter>());
        regionAdapterMappings.RegisterMapping(typeof(ItemsControl), ServiceLocator.Current.GetInstance<ItemsControlRegionAdapter>());
        regionAdapterMappings.RegisterMapping(typeof(ContentControl), ServiceLocator.Current.GetInstance<ContentControlRegionAdapter>());
    }
    return regionAdapterMappings;
}

領域ビヘイビア

Region Behaviors

領域ビヘイビアは、領域のための機能のほとんどを与えるPrism Libraryで使用されています。ブートストラップ工程の間、ブートストラッパーは、既定で、各々の領域に添付される領域ビヘイビアを登録します。さらに、アダプタは、領域が、特定のコントロール型だけで、関連付けられるとき、ビヘイビアを追加するかもしれません。

すべての領域のための領域ビヘイビアを追加する

Adding a Region Behavior for All Regions

あなたが、ビヘイビアを作成するか、既存のものを拡張したあと、あなたは、それを登録することができます。それで、それは、すべての新しい領域に追加されます。あなたは、ブートストラッパー内の、ConfigureDefaultRegionBehaviorsを上書きすることで、行うことができます。次のコード例は、すべての領域のカスタム・ビヘイビアを、どのように、追加するかを示します。

protected override IRegionBehaviorFactory ConfigureDefaultRegionBehaviors()
{
    IRegionBehaviorFactory factory = base.ConfigureDefaultRegionBehaviors();
    factory.AddIfMissing("MyBehavior", typeof(MyCustomBehavior));
}

一つの領域のための領域ビヘイビアを追加する

Adding a Region Behavior for a Single Region

次のコード例は、領域ビヘイビアを一つの領域に、どのように、追加するかを示します。

IRegion region = regionManager.Region\["Region1"\];
region.Behaviors.Add("MyBehavior", new MyRegion());

既存の領域ビヘイビアを置き換える

Replacing an Existing Region Behavior

あなたが、既定のビヘイビアを、異なるビヘイビアに置き換えたい場合、あなたは、あなたのアプリケーション固有のブートストラッパーで、ConfigureDefaultRegionBehaviorsメソッドを上書きすることで、それを追加することができます。そして、あなたのビヘイビアを、既定のビヘイビアとして、同じキー値と一緒に登録します。Prism Libraryは、そのキーと一緒にビヘイビアが、すでに追加されていない場合のみ、既定の領域ビヘイビアを追加します。

時折、あなたは、個々のView上に、領域ビヘイビアを、領域に追加、あるいは、置き換えたいかもしれません。それらの領域が、XAML内で定義される場合、ほとんどの領域のように、領域は、あなたのカスタム・ビヘイビアを添付するために、最初に、利用できないかもしれません。領域が、利用できるようになるとき、あなたは、領域の有効性を監視し、そして、あなたのビヘイビアを添付する必要があります。次のコード例は、領域が、利用できるようになるとき、AutoPopulateBehaviorを、あなたのカスタム・バージョンに、どのように、置き換えるかを示します。

public class MyView : UserControl
{
    public MyView()
    {
        InitializeComponent();

        ObservableObject<IRegion> observableRegion = RegionManager.GetObservableRegion(this.MyRegionHostControl);

        observableRegion.PropertyChanged += (sender, args) =>
        {
            IRegion region = ((ObservableObject<IRegion>)sender).Value;
            region.Behaviors.Add(AutoPopulateBehavior.BehaviorKey,
                new CustomAutoPopulateBehavior());
        };
    }
}

領域ビヘイビアを削除する

Removing a Region Behavior

それが追加されたあと、既存のビヘイビアを削除する方法がありませんが、あなたは、あなたのアプリケーション固有のブートストラッパーで、ConfigureDefaultRegionBehaviorsメソッドを上書きすることによって、ビヘイビアが追加されるのを妨げることができます。

Viewが、どのように、発見されるかを変更する

Changing How Views Are Discovered

View発見を使用するとき、あなたは、Viewが、どのように、登録、あるいは、作成されるかを制御したいかもしれません。 以下は、View発見を拡張するためのアプローチです。:

  • カスタムRegionViewRegistry。あなたが、型の登録についての追加のコントロールを持ちたい(たとえば、レジストリのスコーピング)あるいは、あなたの型の作成を制御したい場合、あなたは、このクラスから派生する必要があります。
  • カスタムAutoPopulateBehavior。あなたが、その登録されたViewで、どこの領域で発見するかを変更したい場合、(あなたが、RegionViewRegistryを使用したくない場合)あなたは、Viewが、実際に、領域に追加されるが変更したい場合、(たとえば、あなたが、フィルタリングするための機能を提供したい場合)、あなたは、すべての領域のための、一つの領域、あるいは、既定に変更するために、カスタムAutoPopulateBehaviorを作成することができます。

領域ナビゲーション。

Region Navigation

次のセクションでは、Prism Libraryの領域ナビゲーション機能を、どのように、拡張するかを説明します。

あなたの論理的ナビゲーション構造を変更する

Changing Your Logical Navigation Structure

Prism Libraryの領域ナビゲーション機能は、ナビゲーション統一リソース識別子 (URI)として、各々のviewの型名を使用します。あなたのアプリケーションは、View型名から独立した、URIナビゲーション・スキームを公開したいかもしれません。

WPFアプリケーションは、同じ結果を得るために、IRegionNavigationContentLoader実装を置き換えることができます。また、多標的アプリケーションは、この方法を使用する、アプリケーションのためのURI構造が定義される一つの場所を維持することを望むかもしれません。

論理的ナビゲーション構造を変更するには、RegionNavigationContentLoaderから新しいクラスを派生し、GetContractFromNavigationContextメソッドを上書きします。メソッド内で、読み込むView型名を、入力契約名に変換します。都合良く、検査する契約文字列にURIを解析するため、基底クラスを呼び出すために、推奨されます。次のコード例は、Home」をHomeビューに、そして、「About」をAboutビューにマッピングするカスタム領域のコンテンツ・ローダーを示します。

備考: この例では、エクスポート属性は、MEFコンテナで利用できるように、クラスの一番上に、適用して、MEFを使用します。

[Export(typeof(IRegionNavigationContentLoader))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class CustomRegionNavigationContentLoader : RegionNavigationContentLoader
{
    [ImportingConstructor]
    public CustomRegionNavigationContentLoader(IServiceLocator serviceLocator)
        : base(serviceLocator)
    {
    }

    protected override string GetContractFromNavigationContext(NavigationContext navigationContext)
    {

        string contract = base.GetContractFromNavigationContext(navigationContext);
    
        if (contract.Equals("Home", StringComparison.OrdinalIgnoreCase))
        {
            return typeof(HomeView).Name;
        }

        if (contract.Equals("About", StringComparison.OrdinalIgnoreCase))
        {
            return typeof(AboutView).Name;
        }
    
        return contract;
    }
}

あなたが、カスタム・ナビゲーション・コンテンツ・ローダーを持ったあと、それを、コンテナ内のIRegionNavigationContentLoaderの実装として、置き換えます。コンテナ内で、置き換える型の詳細については、このトピックの初めの、コンテナとBootstrapperの項目を参照してください。

高等なナビゲーションの置き換え

Advanced Navigation Replacements

次のセクションでは、Prism Libraryで、提供される領域ナビゲーション基盤構造の主要な部分を置き換えることを説明します。ほとんどの開発者は、カスタマイズのこのレベルを必要とするシナリオを持っていません。

RegionNavigationContentLoader

RegionNavigationContentLoader型は、IRegionNavigationContentLoaderインターフェイスを実装しています。あなたは、RegionNavigationContentLoaderから派生する、メソッドを上書きするかもしれません。あるいは、完全にインターフェイスの実装を置き換えます。

LoadContentメソッドに加えて、RegionNavigationContentLoader型は、上書きするために、2つの他の可能なメソッドを持っています。しかし、それらは、珍しい、ナビゲーション・シナリオを、一つだけ必要する必要があります。:

  • GetCandidatesFromRegion。ナビゲーションの要求を処理するための候補の、このメソッドは、領域で、Viewを決定するフィルタを使用します。特別なフィルタリングを行う、あるいは、候補ビューの並べ替えをする必要があるアプリケーションは、このメソッドを上書きする必要があります。
  • CreateNewRegionItem。このメソッドは、ナビゲーションの要求を取り扱うことができる候補が、見つからない場合、Viewを作成するために呼び出されます。IServiceLocatorを使用する既定の実装は、Viewのインスタンスを作成します。アプリケーションは、コンテナの外側に、このメソッドを上書きするためのViewのインスタンスやシングルトンを返すために、特別なロジックを必要とします。

IRegionNavigationJournal/IRegionNavigationJournalEntry

領域ナビゲーション・サービスには、ナビゲーション履歴を記録するジャーナルが含まれています。そして、「戻る」と「進む」ナビゲーションを提供します。既定の実装は、標準的なスタック実装です。アプリケーションは、より高等な履歴と履歴機能を実装することを望みます。 (Internet ExplorerのBackボタンのドロップダウン・メニューのような)ビヘイビアを変更するために、RegionNavigationJournalを置き換える必要があるかもしれません。そして、追加のデータを与えるために、各々の入力によるTitle領域とIcon領域のような、RegionNavigationJournalEntryを置き換える必要があるかもしれません。

IRegionNavigationService

ViewModelロケーター

View Model Locator

ViewModelロケーターは、その標準的な規則を使用して、ViewとView Modelを接続するために、MVVMの基本的なQuickStartで使用されます。この項目は、Viewの命名と配置、命名、関連付け、関連するViewModelとViewの配置の規則を、どのように、変更するかを説明します。

ViewModelロケーターを使用するか、あるいは、MEFを使用して、あなたのViewとViewModelを互いに接続するか、決定するための説明については、以下を参照して下さい。バックグラウンドとして、株トレーダーのリファレンス実装は、ViewとView Modelを接続するMEFを使用します。

View Model Locator規則を変更する

Changing the View Model Locator Conventions

ViewModelLocationProviderは、ViewModelに、Viewを関連付けるための、あなた独自の規則を提供するために、使用できるSetDefaultViewTypeToViewModelTypeResolverと呼び出される静的メソッドを提供します。

ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) =>
{
    ...
    return viewModelType;
});

既定では、View名前空間に配置される場合、Viewは、ViewModelに名前空間を更新する、そして、Viewの名前に「ViewModel」接尾辞を添付するでしょう。Prismは、同じアセンブリで、このViewModelを探すでしょう。

コンテナを使用するために、ViewModelLocationProviderを設定する

Configuring the ViewModelLocationProvider to Use a Container

次の例は、コンテナを使用して、ViewModelを構築するために、ViewModelLocationProviderを、どのように、設定するかを示します。

あなたのアプリケーションを起動する時、VieModel型を解決するためのあなたのコンテナを使用するために、SetDefaultViewModelFactoryメソッドを使用します。以下は、MicrosoftのUnity依存関係注入コンテナを使用する例です。

IUnityContainer _container = new UnityContainer();
...
ViewModelLocationProvider.SetDefaultViewModelFactory((t) => _container.Resolve(t));

あなたが、ViewModel内に、既定のコンストラクタを持っている、そして、注入される依存関係がない場合、ViewModelを作成するための既定の戦略は、有効なアプローチのActivator.CreateInstanceメソッドを使用することです。

このエントリーをはてなブックマークに追加

Home PC C# Illustration

Copyright (C) 2011 Horio Kazuhiko(kukekko) All Rights Reserved.
kukekko@gmail.com
ご連絡の際は、お問い合わせページのURLの明記をお願いします。
「掲載内容は私自身の見解であり、所属する組織を代表するものではありません。」