Prism 5.0 for WPFのHello Worldをはじめから作成してみる
広告
Prism 5.0 for WPF パッケージに入っているQS-Hello World QuickStartのドキュメントの場所が見つかったので、 ドキュメントを参考に、C# WPFでPrismを使用して、Hello Worldを表示するプログラムの作成にチャレンジしました。 しかし、動きません。すでに動作を確認したQS-Hello World QuickStartサンプルコードと比較すると、 ドキュメントの内容が、ところどころ内容が異なっています。
結果として、動かなかったのですが、操作手順を記録しておきます。
これまでの経緯
ある程度の周辺情報を理解していると、どこを探すと必要な情報に出会えるか推測できるのでしょうが、 C#のWPFに関連する情報は、存在はするのですが、理解するのが困難です。 そして、WPFを使用してプログラミングする際には、 MVVMデザインパターンを意識したほうが良いという情報が頻繁に出てくするのですが、 実際に、C#でWPFを使用する際にどう使えばいいのかは、皆目検討が付きません。
そんな中、本当か、嘘かは知りませんが、 MVVMデザインパターンは、C#をWPFだけで利用するには、困難で、現実的には、ツールキットを使う必要があるという情報を見つけました。 調べてみると「Prism」や「MVVM Light Toolkit」などのMVVMでの実装を支援するツールキットが存在します。
ドキュメントが、多そうな「Prism」に挑戦しようと決めました。
そして、「Prism 5.0 for WPF」という、ドキュメント、サンプルコードのパッケージをダウンロードしました。
今回の内容
既に、完成しているサンプルコードを実行するだけでは。何の役にも立ちません。 最初から、アプリケーションを作成する方法を確認する必要があります。
Prism 5.0 for WPF内のHello Worldのドキュメントを見つけました。
原文
17: Getting Started Using the Prism Library 5.0 for WPF Hands-on Lab
和訳
17: Prism Library 5.0 for WPF hands-on labを使用して、開始する。
その説明に従って、アプリケーションを初めから作成します。
実際に作成する
プロジェクトを作成します。
Visual Studioで、「ファイル」→「新規作成」→「プロジェクト」を選択します。
※Visual Studio Community 2015を使用しました。
新しいプロジェクトダイアログで、テンプレートから、「Windows」、「WPFアプリケーション」を選択します。 場所は、新たにPrsimフォルダを作成し、プロジェクトの名前として、HelloWorld.Desktopに設定します。
アプリケーション・テンプレートが作成されました。
Prismライブラリを、NuGetを使用して、追加します。追加するパッケージは、次の2つです。
- Prism
- Prism.UnityExtensions
では、実際に追加します。 ソリューションエクスプローラー内で、参照を選択し、右クリックします。 表示されるコンテキストメニューで、「NuGetパッケージの管理」を選択します。
検索ボックスに「prism」を入力して、目的とするNuGetパッケージを選択します。 リストの一番上に、「Prism」が表示されるので、インストールします。
プレビューダイアログが表示されるので、OKをクリックします。
ライセンスへの同意ダイアログが表示されます。「同意する」をクリックするとインストールが実行されます。
インストールが完了したら、検索ボックスに「Prism.Unity」を入力し、 検索結果のリストに表示される「Prism.UnityEXtensions」を選択し、インストールをクリックします。
プレビューダイアログが表示されるのでOKをクリックします。
ライセンスの同意ダイアログが表示されます。「同意する」をクリックするとインストールが始まります。
更新プログラムの存在がアピールされているので、「更新プログラム」をクリックし、検索ボックスのテキストを削除します。 Unityを除く項目にチェックを入れ、更新をクリックします。 Unityを外したのは、パッケージに含まれていた完成したプロジェクトをビルドした際、v4.01でエラーが発生しためです。
参考:
C# WPFで、Prismを使いはじめるための環境構築に関する試行錯誤 - ドローイング空間
プレビューダイアログが表示されるのでOKをクリックします。
ライセンスの同意ダイアログが表示されます。「同意する」をクリックするとインストールが始まります。
NuGetタブを閉じます。
シェルウインドウを作成します。
シェルウィンドウは、Prism Libraryに基づいた、アプリケーションの最上位のウインドウです。
シェルウィンドウを設定するには
Solution Explorerで、ファイルMainWindow.xamlの名前をShell.xamlに変更します。
Solution Explorerで、ファイルMainWindow.xamlで右クリックして、「名前を選択」しShell.xamlに変更します。
MainWindow.xamlがShell.xamlに変更されるだけでなく、MainWindow.xaml.csがShell.xaml.csに変わります。
Shell.xaml.csを開き、クラス名 MainWindowで右クリックして、コンテキストメニューを開き、「名前の変更」を選択します。
クラス名 MainWindowをShellに変更します。
次に、Shell.zamlを開きます。WindowタグのTitle属性をHello Worldに変更します。
※Communityエディションを使っているので、 名前空間定義xmlnsに、d、mc、local、が追加されています。Expressエディションでは存在しません。
Shellウインドウに、ItemsControlコントロールを追加できるようにするために、 名前空間定義xmlnsを追加します。GridタグをItemsControlタグに変更します。
デザインビューの表示です。この時点では、mainwindow.xamlが存在しないため、ビルドできません。
ItemsControlコントロール定義で、次のコードで示すように、 添付プロパティprism:RegionManager.RegionNameを「MainRegion」に設定します。
<ItemsControl Name="MainRegion" prism:RegionManager.RegionName="MainRegion"/>
備考
シェルウィンドウが、インスタンスを生成するとき、WPFは、prism:RegionManager.RegionName添付プロパティの値を解決します。 そして、RegionManagerクラスで、コールバックを呼び出します。 このコールバックは、領域を作成し、それを、ItemsControlコントロールと関連付けます。
ブーストラッパー
ブートストラッパーは、Prism Libraryを使用する、アプリケーションの構築の初期化のための役割を果たします。 Prism Libraryには、UnityBootstrapperとMefBootstrapperクラスが含まれています。 それは、あなたのアプリケーションのコンテナとして、 UnityやMEFのどちらでも使用するために必要な機能のほとんどを実装しています。 あなたが、UnityやMEF以外のコンテナを使用している場合、 あなたは、あなた独自のコンテナ固有のブートストラッパーを記述する必要があります。
アプリケーションのブートストラッパーを設定する
Bootstrapper.csの内容
HelloWorldプロジェクトに、Bootstrapper.csという名前の新しいクラス・ファイルを追加します。
ソリューションエクスプローラーで、右クリックし、「追加」→「クラス」を選択します。
クラス・ファイルに、Bootstrapper.csという名前を付けます。
Bootstrapper.csが追加されました。
Bootstrapper.csを開き、usingステートメントを変更します。
using System.Windows;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Prism.UnityExtensions;
using Microsoft.Practices.Unity;
UnityBootstrapperクラスから継承する、Bootstrapperクラスの署名を更新します。
class Bootstrapper : UnityBootstrapper
{
}
Bootstrapperクラスで、CreateShellメソッドを上書きします。 次のコードで示すように、このメソッドでは、シェルウィンドウのインスタンスを作成して、それを返します。
protected override DependencyObject CreateShell()
{
return new Shell();
}
ブートストラッパー・クラスで、InitializeShellメソッドを上書します。これメソッドでは、ユーザーに、シェルを表示します。
protected override void InitializeShell()
{
base.InitializeShell();
Application.Current.MainWindow = (Window)this.Shell;
Application.Current.MainWindow.Show();
}
ConfigureModuleCatalogメソッドを上書きします。 このテンプレート・メソッドでは、あなたは、モジュールとモジュール・カタログを埋め込みます。
protected override void ConfigureModuleCatalog()
{
base.ConfigureModuleCatalog();
}
これで、Bootstrapper.csの書き込みは終了です。
Bootstrapper.csは、現在、以下の様な内容になっています。
using System.Windows;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Prism.UnityExtensions;
namespace HelloWorld
{
class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
return new Shell();
}
protected override void InitializeShell()
{
base.InitializeShell();
Application.Current.MainWindow = (Window)this.Shell;
Application.Current.MainWindow.Show();
}
protected override void ConfigureModuleCatalog()
{
base.ConfigureModuleCatalog();
}
}
}
App.xaml.csの修正
次に、App.xaml.csの内容を修正します。
次のコードで示すように、ファイルApp.xaml.csを開き、そして、アプリケーションのStartupイベントのための、 ハンドラ内のBootstrapperを初期化します。 これを行うことによって、アプリケーションの起動時に、ブートストラッパー・コードは、私たちが実行するでしょう。
修正前
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace HelloWorld.Desktop
{
/// <summary>
/// App.xaml の相互作用ロジック
/// </summary>
public partial class App : Application
{
}
}
修正後
using System.Windows;
namespace HelloWorld
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Bootstrapper bootstrapper = new Bootstrapper();
bootstrapper.Run();
}
}
}
App.xamlの修正
App.xamlファイルを開き、そして、属性StartupUriを削除します。x:Class名をHelloWorld. Appに変更します。 あなたは、手動で、ブートストラッパーで、シェルウィンドウをインスタンス化するため、この属性は、必要ありません。 App.xamlファイルのコードは、次に示のようになります。
修正前
<Application x:Class="HelloWorld.Desktop.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:HelloWorld.Desktop"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
修正後
<Application x:Class=" HelloWorld. App "
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:HelloWorld.Desktop">
<Application.Resources>
</Application.Resources>
</Application>
アプリケーションをビルドして、実行します。
空のHello Worldウィンドウが、表示されました。 Mainwindow.xamlが存在しないのに、実行できていることが気持ち悪く感じていると思います。
モジュールを追加する
モジュールをソリューションに追加します。モジュールは、ソリューションの論理ユニットです。 モジュールは、クラスライブラリに記述します。
新たに、クラスライブラリHelloWorldModuleを追加します。
あなたのソリューションに、新しいクラス・ライブラリ・プロジェクトを追加します。 ソリューション・エクスプローラーで、HelloWorld.Desktopソリューション・ノードを右クリックし、 追加を指し、そして、新しいプロジェクトをクリックします。
※白系のカラーテーマは、目が痛くなったので、濃色系に変更しました。
Project型リストで、Visual C#ノードのWindowsを選択します。Templateボックスで、クラス・ライブラリをクリックします。 最後に、プロジェクトの名前を、HelloWorldModuleに設定し、そして、OKをクリックします。
ソリューションエクスプローラーにクラスライブラリが追加されました。
作成したHelloWorldModuleクラスライブラリに、参照を追加する
ソリューション・エクスプローラーで、HelloWorldModuleプロジェクトの参照を右クリックします。 そして、参照を追加をクリックします。
参照の追加ダイアログボックスで、Assembliesタブを選択し、 続いて、次に示すアセンブリのチェックボックスにチェックを入れ、そして、OKをクリックします。
- PresentationCore.dll
- PresentationFramework.dll
- WindowsBase.dll
- System.Xaml.dll
次のPrism Libraryアセンブリに、あなたのモジュールの参照を追加します。
インストール済みパッケージ・ボタンをクリックします。Prismを選択し、 Selected Projectsダイアログで、HelloWorldModuleを選択し、そして、OKをクリックします。
プレビューダイアログが表示されるので、OKをクリックします。
ライセンスの同意ダイアログが表示されます。「同意する」をクリックするとインストールが始まります。
インストールが終了したら、「NuGet-ソリューション」タブを閉じます。
Class1.csファイルの名前をHelloWorldModule.csに変更します。
Class1.csファイルで、右クリックして、「名前の変更」をします。
名前を変更します。
「はい」を選択します。
HelloWorldModule.csを開いてコードを追加します。
usingステートメントを追加します。
using Microsoft.Practices.Prism.Modularity
IModuleインターフェイスを実装するために、クラス署名を変更します。
public class HelloWorldModule : IModule
{
}
HelloWorldModuleクラス内に、次のコードの示される、Initializeメソッドの空の定義を追加します。
public void Initialize()
{
}
このようになります。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Prism.Modularity;
namespace HelloWorldModule
{
public class HelloWorldModule : IModule
{
public void Initialize()
{
}
}
}
HelloWorldModuleプロジェクトに、Viewフォルダを追加する
HelloWorldModuleプロジェクトに、Viewフォルダを追加します。このフォルダに、Viewの実装を格納します。
Viewフォルダを追加しました。
今回は使用しないので、追加しませんが、ここに、必要に応じて、ServicesとViewModelsのフォルダを追加します。
- Services。このフォルダで、あなたは、サービス実装とサービス・インターフェイスを格納します。
- ViewModels。このフォルダに、あなたは、View Modelを格納します。
アプリケーションのライフサイクルモジュール
ここで、モジュールが、アプリケーションの起動時に行う3つの工程について理解しておきます。
モジュールマネージャーサービスで、
- モジュールカタログで、モジュールを見つける。
- モジュールを初期化する。
- モジュールをインスタンス化し、モジュールのInitializeメソッドを呼び出します。
ここでは、この工程を実現するためのコードを実装します。
モジュールカタログを埋め込む
Prism Libraryは、モジュール・カタログを埋め込む、いくつかの方法を提供します。 コードから、XAMLファイルから、設定ファイルから、 あるいは、ディレクトリから、モジュール・カタログを埋め込むことができます。
それでは、実際に、HelloWorld.Desktopアプリケーションに、 HelloWorldModuleモジュールを読み込むカタログを、 コードから、どのように埋め込むかについて説明します。
HelloWorld.Desktopの参照を追加する
HelloWorld.Desktopプロジェクトに、HelloWorldModuleプロジェクトの参照を追加します。
ソリューション・エクスプローラーから、HelloWorld.Desktopの参照で右クリックし、「参照の追加」を選択します。
表示される参照マネージャーダイアログで、プロジェクトを選択し、 HelloWorld.Desktopのチェックボックスにチェックを入れ、OKをクリックします。
Bootstrapper.csファイルを開き、ConfigureModuleCatalogメソッドを修正します。
修正前
protected override void ConfigureModuleCatalog()
{
base.ConfigureModuleCatalog();
}
修正後
protected override void ConfigureModuleCatalog()
{
base.ConfigureModuleCatalog();
ModuleCatalog moduleCatalog = (ModuleCatalog)this.ModuleCatalog;
moduleCatalog.AddModule(typeof(HelloWorldModule.HelloWorldModule));
}
この時点での、Bootstrapper.csは、以下のようになっています。
using System.Windows;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Prism.UnityExtensions;
namespace HelloWorld
{
// UnityBootstrapperクラスから継承する、Bootstrapperクラスの署名を更新します。
class Bootstrapper : UnityBootstrapper
{
// Bootstrapperクラスで、CreateShellメソッドを上書きします。
protected override DependencyObject CreateShell()
{
return new Shell();
}
// ブートストラッパー・クラスで、InitializeShellメソッドを上書します。
protected override void InitializeShell()
{
base.InitializeShell();
Application.Current.MainWindow = (Window)this.Shell;
Application.Current.MainWindow.Show();
}
protected override void ConfigureModuleCatalog()
{
base.ConfigureModuleCatalog();
ModuleCatalog moduleCatalog = (ModuleCatalog)this.ModuleCatalog;
moduleCatalog.AddModule(typeof(HelloWorldModule.HelloWorldModule));
}
}
}
ソリューションをビルドして、実行します。HelloWorldModuleモジュールが、初期化されていることを確認するには、 HelloWorldModuleクラスのInitializeメソッドに、ブレークポイントを追加します。赤い丸がブレークポイントです。
ブレークポイントに衝突すると、赤い丸が矢印に変わります。
ビューを追加する
ViewをHelloWorldModuleモジュールに作成し、そして、追加します。Viewは、外観の内容が含まれているオブジェクトです。 Viewは、多くの場合、ユーザー・コントロールですが、それらは、ユーザー・コントロールである必要はありません。
Solution Explorerで、Viewフォルダを右クリックし、追加を指し、そして、新しい項目をクリックします。
新しい項目の追加ダイアログボックスで、ユーザー・コントロール(WPF)テンプレートを選択し、 名前を、HelloWorldView.xamlに設定し、そして、追加をクリックします。
Gridタグ内に、以下のコードを追加します。
<TextBlock Text="Hello World" Foreground="Green" HorizontalAlignment="Center"
VerticalAlignment="Center" FontFamily="Calibri" FontSize="24" FontWeight="Bold"></TextBlock>
デザインビューは、このように表示されています。
HelloWorldView.xamlのコードを全体は、次のようになっています。
<UserControl x:Class="HelloWorldModule.View.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:HelloWorldModule.View"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBlock Text="Hello World" Foreground="Green" HorizontalAlignment="Center"
VerticalAlignment="Center" FontFamily="Calibri" FontSize="24" FontWeight="Bold"></TextBlock>
</Grid>
</UserControl>
ファイルは、作業の合間に適時保存してください。
領域マネージャー
領域マネージャー・サービスは、領域のコレクションを保持するための役割を果たします。 そして、コントロールのために、新しい領域を作成します。 このサービスは、Microsoft.Practices.Prism.Regions.IRegionManagerインターフェイスを実装しています。 名前を通して分離された方法で、領域を配置するために、直接、このサービスと相互作用します。
HelloWorldModule.csファイルを開きます。Prism Libraryで領域要素を参照するために、次のusingステートメントを追加します。
using Microsoft.Practices.Prism.Regions
領域マネージャーへの参照を格納するために、公開されない読取専用インスタンス変数を作成します。 これを実行するには、クラス・ボディの中に、次のコードを貼り付けます。
これを実行するには、クラス・ボディの中に、次のコードを貼り付けます。
private readonly IRegionManager regionManager;
コンストラクタの依存関係注入を通じて、領域マネージャー・インスタンスを取得するために、
HelloWorldModuleクラスのコンストラクタを追加します。
そして、それをregionManagerインスタンス変数に格納します。
これを実行するには、コンストラクタは、型Microsoft.Practices.Prism.Regions.IRegionManagerのパラメータを取得する必要があります。
あなたは、コンストラクタを実装するために、クラス・ボディの中に、次のコードを貼り付けることができます。
public HelloWorldModule(IRegionManager regionManager)
{
this.regionManager = regionManager;
}
Initializeメソッドでは、RegionManagerインスタンスで、RegisterViewWithRegionメソッドを呼び出します。 このメソッドは、領域Viewレジストリ内に、その関連するビュー型で、領域の名前を登録します。; レジストリは、これらのマッピングを登録、そして、取得するための役割を果たします。 RegisterViewWithRegionメソッドは、2つのオーバーロードを持っています。: あなたが、直接、Viewを登録したいとき、 あなたは、領域の名前とViewの型の2つのパラメータを必要とする、最初のオーバーロードを使用します。
public void Initialize()
{ regionManager.RegisterViewWithRegion("MainRegion", typeof(Views.HelloWorldView));
}
前述のコードで使用されるUI構成アプローチは、View発見として知られています。 この方法を使用するとき、あなたは、Viewと、Viewが読み込まれる領域を指定します。 領域が作成されるとき、それは、その関連するViewを要求し、自動的に、それを読み込みます。
全体のコードは、次のようになります。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Prism.Regions;
namespace HelloWorldModule
{
public class HelloWorldModule : IModule
{
private readonly IRegionManager regionManager;
public HelloWorldModule(IRegionManager regionManager)
{
this.regionManager = regionManager;
}
public void Initialize()
{
regionManager.RegisterViewWithRegion("MainRegion", typeof(Views.HelloWorldView));
}
}
}
アプリケーションをビルドして、実行します。エラーが発生します。
サンプルコードと比較すると、「
IRegionManager regionManager
」 ではなく「
IRegionViewRegistry regionViewRegistry
」が使われています。 しかし、ここだけを修正してもエラーが解消されません。他の部分もいろいろ異なっているようです。
サンプルコードのHelloWorldModule.csファイル
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Prism.Regions;
namespace HelloWorldModule
{
public class HelloWorldModule : IModule
{
private readonly IRegionViewRegistry regionViewRegistry;
public HelloWorldModule(IRegionViewRegistry registry)
{
this.regionViewRegistry = registry;
}
public void Initialize()
{
regionViewRegistry.RegisterViewWithRegion("MainRegion", typeof(Views.HelloWorldView));
}
}
}
このソリューションを修正して、動くようにするか、既に動作しているサンプルコードを元に、 操作方法をまとめなおすことにするか、判断に迷いましたが、 既に動作しているサンプルコードを元に、操作方法をまとめなおすことにして、 このプロジェクトは、ここで終了することにしました。
今後の予定
このプロジョクトを修正するのはあきらめ、既に動作しているサンプルコードを元に、操作方法をまとめなおすことにします。