Prismについて

正直、この記事を読んでいる方には、今さら説明は不要でしょう。

特にこの記事はWPFを中心に書いているため、WPFとPrismといえばMVVMのためのライブラリ。そのPrismについて徹底解説をしていこうと思います。

PrismLibrary/Prism-Samples-Wpf

01-BootstrapperShell

正直、このサンプルに戸惑った人は多いのではないでしょうか?

Descriptionoには Create a basic bootstrapper and shell と書かれています。

初期プロジェクトから書き換え、追記されているのは以下の通りです。

App.xaml

<Application
    x:Class="BootstrapperShell.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:BootstrapperShell">
    <Application.Resources />
</Application>

App.xaml.cs

using System.Windows;

namespace BootstrapperShell
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            var bootstrapper = new Bootstrapper();
            bootstrapper.Run();
        }
    }
}

MainWindow.xaml

<Window
    x:Class="BootstrapperShell.Views.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Shell"
    Width="525"
    Height="350">
    <Grid>
        <ContentControl Content="Hello from Prism" />
    </Grid>
</Window>

Bootstrapper.cs

using System.Windows;
using BootstrapperShell.Views;

namespace BootstrapperShell
{
    class Bootstrapper : PrismBootstrapper
    {
        protected override DependencyObject CreateShell()
        {
            return Container.Resolve<MainWindow>();
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry) { }
    }
}

ざっくり言うと App.xaml.cs から Bootstrapper インスタンスを生成して、それを走らせ Run するわけですね。 で Bootstrapper.cs では PrismBootstrapper という、よく分からないブートストラッパが継承されています。

実際 Bootstrapper.cs のメソッドは override です。Prismがよろしくやってくれてるわけですね。

この CreateShell() では Bootstrapper クラスで MainWindow インスタンスに対して、 何がシェルクラスであるか、すなわちアプリの土台になるクラスを返しているわけです。

ブートストラッパと聞くと、なんか凄いことやってくれそうな気がしてますけど、ただ土台となるクラスのインスタンスを作成して返してるだけですよ…

Bootstrapper.xaml ですか?そんなのありませんよ。裏で何らか生成されているかもしれませんが今の私にはわかりません、 結局 <ContentControl Content="Hello from Prism" /> で渡した「Hello from Prism」が Content として表示されている、それだけのサンプルです。

うん、WPFでだったら Label で作るだけで済む話のやつですけどね…きっと、これが出発点なんですよ!

その割には、Prismのサンプルコードって最初から飛ばしてますよね…

02-Regions

こっちは、実際動かしても本当に意味がわかりませんね。

Descriptionには Create a region って書いてありますね、region って何だよ。

01-BootstrapperShell にあった Bootstrapper.cs が消えて、こんな感じになってます。

App.xaml

<prism:PrismApplication
    x:Class="Regions.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Regions"
    xmlns:prism="http://prismlibrary.com/">
    <Application.Resources />
</prism:PrismApplication>

App.xaml.cs

using System.Windows;
using Regions.Views;

namespace Regions
{
    /// <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) { }
    }
}

MainWindow.xaml

<Window
    x:Class="Regions.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">
    <Grid>
        <ContentControl prism:RegionManager.RegionName="ContentRegion" />
    </Grid>
</Window>

まずわかるのは、App クラスが PrismApplication を継承していることです。

おそらくですが…シェルクラスではなく、App クラスをシェルとして渡すというサンプルでしょう。

これ…初見で動かして理解できる人、いるんでしょうか?

ChatGPTによると「リージョンとは特定の領域にコンテンツを動的に表示できる仕組み」らしいです。

多分この後に出てくるんでしょうけど、本当に最初から飛ばしまくりで…これ学ぶのキッツいでしょ… 感じるのは、この PrismApplication 継承が DI(依存性注入) の伏線になってる気がするんですよね。

CommunityToolkit.Mvvm では DI するために、interface を記述して継承したクラスを登録する…という仕組みでしたけど。例えばこんな感じね

services.AddSingleton<IMainWindowViewModel, MainWindowViewModel>();

このような記述無しで、DI が実現できるとしたら確かに美味しいかもしれない。

03-CustomRegions

Descriptionには Create a custom region adapter for the StackPanel と書いてありますね…だけど StackPanel は表示されないしで… はい、これも全く意味不明です、動かしたところで何もわかりません。

App.xaml

前節と同じ

App.xaml.cs

using System.Windows;
using System.Windows.Controls;
using Regions.Views;

namespace Regions
{
    /// <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 ConfigureRegionAdapterMappings(RegionAdapterMappings regionAdapterMappings)
        {
            base.ConfigureRegionAdapterMappings(regionAdapterMappings);
            regionAdapterMappings.RegisterMapping(typeof(StackPanel), Container.Resolve<StackPanelRegionAdapter>());
        }
    }
}

Prism\StackPanelRegionAdapter.cs

using System.Windows;
using System.Windows.Controls;

namespace Regions
{
    public class StackPanelRegionAdapter : RegionAdapterBase<StackPanel>
    {
        public StackPanelRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory)
            : base(regionBehaviorFactory)
        {
        }

        protected override void Adapt(IRegion region, StackPanel regionTarget)
        {
            region.Views.CollectionChanged += (s, e) =>
            {
                if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
                {
                    foreach (FrameworkElement element in e.NewItems)
                    {
                        regionTarget.Children.Add(element);
                    }
                }

                //handle remove
            };
        }

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

注意:ここで「IDE0130 : Namespace “Regions” はフォルダー構造と一致しません。“Regions.Prism” が必要です」が出ますが、素直に直したら動かなくなります。

ごめんなさい、この IDE0130 の解決方法はわかりません。

なんせ、ビルドエラーが起こるのに、エラー一覧に何も表示されないんですもの… “Regions.Prism” ではなく “Regisons.PrismClass” と各種変更すれば通りますが…まあ、Prismフォルダなんて作るのはここだけでしょう。

で、このサンプル…なんらかの region 変更処理を付け加えたのでしょうけど、それを検証できるコードが何もないのでパス!

一旦締めます

いや…このサンプルを読んで、理解できる人どれだけいるんだよ…

まず「region とは何ぞや?」ってなるでしょ?

マジで俺もほとんどわからねぇ…だけど、次回からは違うと思うぞ!

WPFにおけるPrism集中講座(2) regionの謎 に続きます。