07-Modules-AppConfig
Description には Load modules using an App.config file と書かれています。
さて、これは何でしょうね?実行したら「View A」と表示されます。
ソリューションを見てみると、プロジェクト「Modules」と「ModuleA」があります。 おそらく「Modules」から「ModuleA」のView を使っているのでしょう。
App.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="modules" type="Prism.Modularity.ModulesConfigurationSection, Prism.Wpf" />
</configSections>
<startup>
</startup>
<modules>
<module assemblyFile="ModuleA.dll" moduleType="ModuleA.ModuleAModule, ModuleA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="ModuleAModule" startupLoaded="True" />
</modules>
</configuration>
更新されたファイル単体では分かりにくいので、06-ViewActivationDeactivation の App.config を引用してみます。
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
</startup>
</configuration>
はい、見事に空っぽですね。
実際 ModuleA フォルダを bin を基準に掘っていくと ModuleA.dll があります。
では ModuleA にある肝心の変更部分を見てみましょう。
ModuleA\ModuleAModule.cs
using ModuleA.Views;
namespace ModuleA
{
public class ModuleAModule : IModule
{
public void OnInitialized(IContainerProvider containerProvider)
{
var regionManager = containerProvider.Resolve<IRegionManager>();
regionManager.RegisterViewWithRegion("ContentRegion", typeof(ViewA));
}
public void RegisterTypes(IContainerRegistry containerRegistry) { }
}
}
他の変更は些細なものなので省略します。
うん…理屈はなんとなく分かったんだけど、ここまでしてプロジェクト分ける必要があるって、相当大規模なプロジェクトですよね?
少なくとも中規模クラスの開発では、使わないでしょう。 そして、この機能を使う程のプロジェクトであれば、あらかじめ設定されていると思います。
「こういう機能もある」と流して、次行きますよ次!
07-Modules-Code
Description には Load modules using code と書かれています。 これも実行してもわからない奴です。実行したら「View A」と表示されます。 まずは変更点を見てみましょう。
Views\ViewA.xaml.cs
前節と同じです。
App.xaml.cs
using System.Windows;
using Modules.Views;
namespace Modules
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : PrismApplication
{
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry) { }
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
{
moduleCatalog.AddModule<ModuleA.ModuleAModule>();
}
}
}
なんか ConfigureModuleCatalog
オーバーライドメソッドが臭いですね?カタログに登録しているように見えます。
ざっくり「App.config を利用しないで他プロジェクトのモジュールを使う手法」と認識すればいいでしょうねコレ。 さ、次行きますよ次!
07-Modules-Directory
Description には Load modules from a directory と書かれています。 これも、もう予想通りといいますか「View A」と表示されるだけです。肝心なのは中身です。
ModuleA\ModuleAModule.cs
前節と同じです。
App.xaml.cs
using System.Windows;
using Modules.Views;
namespace Modules
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : PrismApplication
{
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry) { }
protected override IModuleCatalog CreateModuleCatalog()
{
return new DirectoryModuleCatalog() { ModulePath = @".\Modules" };
}
}
}
なんか、ソース内にプロジェクトを指すようなパスが含まれてますね?
カタログに、モジュールのパスを追加する…?いや、俺が言うのも何ですが 「正気ですか?」 案件です。
ソースコード内に相対パスとはいえ、プロジェクトのパスを埋め込みますか? 俺から見たら マジックナンバーくらいにヤバい奴 ですよ!
まだ 07-Modules-Code の方が筋がいいと感じました。さ、こんなもの基本使わない方がいいです、次行きますよ次!
07-Modules-LoadManual
Description には Load modules manually using the IModuleManager と書かれています。
これも「View A」を表示するだけ…と言おうと思ったら、度肝を抜かれました。
これ 05-ViewInjection と同等機能ですよ。
Modules 内の App.xaml.cs
using System.Windows;
using ModuleA;
using Modules.Views;
namespace Modules
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : PrismApplication
{
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
}
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
{
var moduleAType = typeof(ModuleAModule);
moduleCatalog.AddModule(new ModuleInfo()
{
ModuleName = moduleAType.Name,
ModuleType = moduleAType.AssemblyQualifiedName,
InitializationMode = InitializationMode.OnDemand
});
}
}
}
Modules 内の Views\MainWindow.xaml
<Window
x:Class="Modules.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
Title="Shell"
Width="525"
Height="350">
<DockPanel LastChildFill="True">
<Button
Click="Button_Click"
Content="Load Module"
DockPanel.Dock="Top" />
<ContentControl prism:RegionManager.RegionName="ContentRegion" />
</DockPanel>
</Window>
Modules 内の MainWindow.xaml.cs
using System.Windows;
namespace Modules.Views
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private readonly IModuleManager _moduleManager;
public MainWindow(IModuleManager moduleManager)
{
InitializeComponent();
_moduleManager = moduleManager;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
_moduleManager.LoadModule("ModuleAModule");
}
}
}
ModuleA 内の ViewA.xaml
前節までと同じです。
…さて、まあ先では 07-Modules-Code の方が筋が良いと言いましたが、こっちの方が全然良いでしょう。
というか、これは若干 IModuleCatalog
が DI コンテナ的に動いているように見えますね。
ただ LoadModule
での引数が文字列なのはいただけない…せっかくの C# なんだから、
今では CommunityToolkit.Mvvm のように C# の機能で実現する方がスマートです。
ただ、これは「モジュールを呼び出すサンプル」なので、あんまり言ってもしょうがないでしょう。
この作りには、若干の古くささを感じますけど…Prism 全盛の時期を考えると、これでも相当凄かったのでしょう。
07-Modules-Xaml
危ない危ない、このサンプルについて言及し損ねるところだった。
というか PrismのGitHub の 表に書いてないんだもの…
Module 内の ModuleCatalog.xaml
<m:ModuleCatalog
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:m="clr-namespace:Prism.Modularity;assembly=Prism.Wpf">
<m:ModuleInfo ModuleName="ModuleAModule" ModuleType="ModuleA.ModuleAModule, ModuleA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</m:ModuleCatalog>
正直、これを見るだけで「あ、はい…」ってなりますよね。だけど次を見てください。
Module 内の App.xaml.cs
using System.Windows;
using Modules.Views;
namespace Modules
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : PrismApplication
{
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry) { }
protected override IModuleCatalog CreateModuleCatalog()
{
return new XamlModuleCatalog(new Uri("/Modules;component/ModuleCatalog.xaml", UriKind.Relative));
}
}
}
XAMLカタログへの登録…これは酷い、いや相対パスよりは URI 使ってるだけマシかも知れませんが…それでも酷い。
上の人が「これを使う」と決めた時以外は、関わらないのが吉な案件ですね…
一旦締めます
サンプルコードは次回から ViewModel に入るようなので、キリがいいここで締めます。
ちなみに追記しておきますと、これほど View で色々できるように作られているのは、Prism が WPF のためのフレームワークだからです。 CommunityToolkit.Mvvm ではここまでのことは できません 。逆に CommunityToolkit.Mvvm は 多くの環境で動きます 。
既に古くさくなった Prism が要件に合うなら止めませんが、 大規模プロジェクトでないなら…今のところ「薦める要素がほとんどない」となります。
CommunityToolkit.Mvvm で作るなら Frame
辺りを使えばいいですからね。
宿題
私が作った SimplePrismViewSample プロジェクトを
MainWindow.xaml.cs 部分を含めて IModuleManager
を利用して書き換えてみてください。
この宿題については、解答を示すつもりはありません。自分で手を動かして、書き換えてみてください。