Prism 5.0 for WPFのHello Worldを実行する(改修版)
広告
Prism 5.0 for WPF パッケージに入っているQS-Hello World QuickStartのドキュメントの場所が見つかったので、 ドキュメントを参考に、C# WPFでPrismを使用して、Hello Worldを表示するプログラムの作成にチャレンジしました。
ところが結果として動きません。 使用要件が、Visual Studio 2013のところをVisual Studio 2015で実行しているので文句は言えませんが、 最初からつまづき、がっかりです。 すでに、動作を確認したQS-Hello World QuickStartサンプルコードと比較するとところどころ内容が異なります。
そこで、サンプルコードをもとに、ドキュメントに記載の方法を参考にして、 実行できるHello Worldアプリケーションの作成手順をまとめることにしました。
今までの経緯
ある程度の周辺情報を理解していると、どこを探すと必要な情報に出会えるか推測できるのでしょうが、 C#のWPFに関連する情報は、存在はするのですが、理解するのが困難です。 そして、WPFを使用してプログラミングする際には、 MVVMデザインパターンを意識したほうが良いという情報が頻繁に出てくするのですが、 実際に、C#でWPFを使用する際にどう使えばいいのかは、皆目検討が付きません。
そんな中、本当か、嘘かは知りませんが、MVVMデザインパターンは、C#をWPFだけで利用するには、困難で、 現実的には、ツールキットを使う必要があるという情報を見つけました。 調べてみると「Prism」や「MVVM Light Toolkit」などのMVVMでの実装を支援するツールキットが存在します。
ドキュメントが、多そうな「Prism」に挑戦しようと決め、ドキュメントを読み始めました。
よくわかりません。
そこで、QS-Hello World QuickStartというサンプルコードを実行しました。 NuGetの更新手順が必要な物のなんとか実行できました。
ドキュメント内に、QS-Hello World QuickStartの説明の項目が見つかったので、その通りにコードを作成しましたが、動きません。 そこで、サンプルコードと比較すると、説明とサンプルコードが、かなり異なることを発見しました。
QS-Hello World QuickStartのドキュメント
サンプルコードを元にして、きちんと実行できるHello World手順をまとめました。Visual Studio Community 2015を使用しました。
Prismライブラリを使用して、Hello Worldを作成します。
プロジェクトを作成します。
Visual Studioで、「ファイル」→「新規作成」→「プロジェクト」を選択します。
新しいプロジェクトダイアログで、テンプレートから、「Windows」、「WPFアプリケーション」を選択します。 場所は、新たにPrsimフォルダを作成し、プロジェクトの名前として、HelloWorld.Desktopに設定します。
アプリケーション・テンプレートが作成されました。
Prismライブラリを追加します。
Prismライブラリを、NuGetを使用して、追加します。追加するパッケージは、次の2つです。
- Prism
- Prism.UnityExtensions
では、実際に追加します。ソリューションエクスプローラー内で、参照を選択し、右クリックします。 表示されるコンテキストメニューで、「NuGetパッケージの管理」を選択します。
検索ボックスに「prism」を入力して、目的とするNuGetパッケージを選択します。 リストの一番上に、「Prism」が表示されるので、インストールします。
プレビューダイアログが表示されるので、OKをクリックします。
ライセンスへの同意ダイアログが表示されます。「同意する」をクリックするとインストールが実行されます。
インストールが完了すると、インストール済みの横に、インストールされたバージョンが表示されます。
インストールが完了したら、検索ボックスに「Prism.Unity」を入力し、 検索結果のリストに表示される「Prism.UnityExtensions」を選択し、インストールをクリックします。
プレビューダイアログが表示されるのでOKをクリックします。
ライセンスの同意ダイアログが表示されます。「同意する」をクリックするとインストールが始まります。
更新プログラムの存在がアピールされているので、「更新プログラム」をクリックし、検索ボックスのテキストを削除します。 Unityを除く項目にチェックを入れ、更新をクリックします。Unityを外したのは、 パッケージに含まれていた完成したプロジェクトをビルドした際、v4.01でエラーが発生しためです。 v4.01以降のバージョンであれば、更新しても問題がでないかもしれません。
参考:
C# WPFで、Prismを使いはじめるための環境構築に関する試行錯誤 - ドローイング空間
プレビューダイアログが表示されるのでOKをクリックします。
ライセンスの同意ダイアログが表示されます。「同意する」をクリックするとインストールが始まります。
Prismライブラリのインストールが終了したので、NuGetタブを閉じます。
シェルウインドウを作成します。
シェルウィンドウは、Prism Libraryに基づいた、アプリケーションの最上位のウインドウです。
ソリューション・エクスプローラーで、ファイルMainWindow.xamlの名前をShell.xamlに変更します。 Solution Explorerで、ファイルMainWindow.xamlで右クリックして、「名前を選択」しShell.xamlに変更します。
MainWindow.xamlの名前をShell.xamlに変更しました。MainWindow.xamlがShell.xamlに変更されるだけでなく、 MainWindow.xaml.csがShell.xaml.csに変わります。 WPFアプリケーションでは、MainWindow.xamlがエントリポイントのため、 後で作成するブートストラップを作成するまで、ビルドできなくなります。
Shell.xaml.csを開き、クラス名 MainWindowで右クリックして、コンテキストメニューを開き、「名前の変更」を選択します。
クラス名 MainWindowをShellに変更します。
名前空間をHelloWorld.Desktopから、HelloWorldに変更します。
コード枠上で、マウスを右クリックして、「usingの整理」→「不要なusingの削除」を選択します。
Shell.xaml.csは、以下の様になります。
using System.Windows;
namespace HelloWorld
{
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class Shell : Window
{
public Shell()
{
InitializeComponent();
}
}
}
次に、Shell.xamlを開きます。WindowタグのTitle属性をHello Worldに変更します。
※Communityエディションを使っているので、名前空間定義xmlnsに、d、mc、local、が追加されています。 このサンプルアプリケーションでは、使用していないので、削除しても問題ありません。 そして、Expressエディションでは存在しません。
アプリケーションの目的が、Hello Worldという文字を表示させるだけなので、 ウインドウサイズを、HeightとWidth属性を変更して、小さくしておきます。
Shellウインドウに、ItemsControlコントロールを追加できるようにするために、名前空間定義xmlnsを追加します。 GridタグをItemsControlタグに変更します。不要な名前空間定義xmlnsを削除します。
ItemsControlコントロール定義で、次のコードで示すように、 添付プロパテcal:RegionManager.RegionNameを「MainRegion」に設定します。
<Window x:Class="HelloWorld.Shell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.codeplex.com/prism"
Title="Hello World" Height="250" Width="300">
<ItemsControl Name="MainRegion" cal:RegionManager.RegionName="MainRegion" />
</Window>
備考
シェルウィンドウが、インスタンスを生成するとき、 WPFは、cal:RegionManager.RegionName添付プロパティの値を解決します。 そして、RegionManagerクラスで、コールバックを呼び出します。 このコールバックは、領域を作成し、それを、ItemsControlコントロールと関連付けます。
デザインビューの表示です。この時点では、MainWindow.xamlが存在しない、 かつ、ブーストラッパーを作成していないため、ビルドできません。
アプリケーションのブートストラッパーを設定する
ブートストラッパーは、Prism Libraryを使用する、アプリケーションの構築の初期化のための役割を果たします。 本来のエントリポイントMainWindow.xamlが、Shell.xamlに名前を変更したため、 既に存在しないので、アプリケーションの起動手順を指定する必要があります。
Prism Libraryには、UnityBootstrapperとMefBootstrapperクラスが含まれています。 それは、あなたのアプリケーションのコンテナとして、UnityやMEFのどちらでも使用するために必要な機能のほとんどを実装しています。 あなたが、UnityやMEF以外のコンテナを使用している場合、 あなたは、あなた独自のコンテナ固有のブートストラッパーを記述する必要があります。
HelloWorldプロジェクトに、Bootstrapper.csという名前の新しいクラス・ファイルを追加します。 ソリューションエクスプローラーで、右クリックし、「追加」→「クラス」を選択します。
クラス・ファイルに、Bootstrapper.csという名前を付けます。
Bootstrapper.csが追加されました。
Bootstrapper.csを開き、usingステートメントを変更します。
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 this.Container.Resolve<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 this.Container.Resolve<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">
<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をクリックします。
ライセンスの同意ダイアログが表示されます。「同意する」をクリックするとインストールが始まります。
インストールが終了したら、「NuGet-ソリューション」タブを閉じます。
Class1.csファイルの名前をHelloWorldModule.csに変更します。
Class1.csファイルで、右クリックして、「名前の変更」を選択します。
名前を変更します。
「はい」を選択します。
HelloWorldModule.csを開いてコードを追加します。
- usingステートメントを追加します。
- IModuleインターフェイスを実装するために、クラス署名を変更します。
- HelloWorldModuleクラス内に、Initializeメソッドの空の定義を追加します。
追加前
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HelloWorldModule
{
public class HelloWorldModule
{
}
}
追加後
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.Views.HelloWorldView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<TextBlock Text="Hello World" Foreground="Green" HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Calibri" FontSize="24" FontWeight="Bold"></TextBlock>
</Grid>
</UserControl>
HelloWorldView.xaml.csを開きます。名前空間をHelloWorldModule.Viewsに変更します。 partial classのクラス名をHelloWorldViewに変更します。不要なusingを削除します。
変更前
namespace HelloWorldModule.View
{
/// <summary>
/// UserControl1.xaml の相互作用ロジック
/// </summary>
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
}
}
変更後
namespace HelloWorldModule.Views
{
/// <summary>
/// UserControl1.xaml の相互作用ロジック
/// </summary>
public partial class HelloWorldView : UserControl
{
public HelloWorldView()
{
InitializeComponent();
}
}
}
領域マネージャー
領域マネージャー・サービスは、領域のコレクションを保持するための役割を果たします。 そして、コントロールのために、新しい領域を作成します。 このサービスは、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を要求し、自動的に、それを読み込みます。
HelloWorldModule.csファイルの全体のコードは、次のようになります。
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));
}
}
}
アプリケーションをビルドして、実行します。完成です。