nuits.jp blog

C#, Xamarin, WPFを中心に書いています。Microsoft MVP for Visual Studio and Development Technologies。なお掲載内容は個人の見解であり、所属する企業を代表するものではありません。

PrismでViewとViewModelのアセンブリを分けたい場合

なんらかの理由で、ViewとViewModelのアセンブリを分割したいことがあるかと思います。

  • ViewModelからViewをうっかり呼ばせたくない
  • ViewModelをきちっと分離して複数のViewから再利用したい
  • なんだかカバレッジでViewModelを綺麗に100%にしたいなあ
  • 趣味

なんて動機がありそうです。
Prismでは通常、Viewと同一のアセンブリ内でViewModelを探索します。
このため、ViewとViewModelのアセンブリを異なるものにしようとした場合、一手間必要になります。
今回はそれを紹介しましょう。
ちなみに、Prism.WPFでもPrism.Formsでも利用可能なテクニックです。 (よく知らないですが多分Prism.Windowsでも)

ViewModelの取得ルール全体を変更したい場合、ViewModelLocationProviderのSetDefaultViewTypeToViewModelTypeResolverメソッドで独自実装したResolverを設定してあげるのが良いでしょう。
具体的には、ViewModelと同じAssemblyに次のようなResoloverクラスを作成します。

    public static class ViewTypeToViewModelTypeResolver
    {
        private static readonly Assembly LocalAssembly = typeof(ViewTypeToViewModelTypeResolver).Assembly;
        public static Type Resolve(Type viewType)
        {
            if (viewType == null) throw new ArgumentNullException(nameof(viewType));

            var vmTypeName = $"{viewType.Namespace.Replace("Views", "ViewModels")}.{viewType.Name}ViewModel";
            return LocalAssembly.GetType(vmTypeName);
        }
    }

なんかAssemblyインスタンスの取得方法がもう少し良いのがありそうな気がするんですが何かないですかね?
まぁ良いや進めましょう。

で、こいつをBootstrapperでConfigureViewModelLocatorをオーバーライドしてやって変更します。

        protected override void ConfigureViewModelLocator()
        {
            base.ConfigureViewModelLocator();
            ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver(ViewTypeToViewModelTypeResolver.Resolve);
        }

こんな感じです。
よかったら使ってあげてください。
それではまた!