読者です 読者をやめる 読者になる 読者になる

ぺぷしのーげん

アプリケーションエンジニア(C#er)による雑記ブログ

WPFのWindowやPageをクラスライブラリ化する方法とその問題点について

f:id:hazakurakeita:20160613224715p:plain

こんにちは、自称ソフトウェアアーキテクトのKeitaです。プログラミングよりもマクロな世界であるソフトウェア設計やアーキテクチャ、フレームワーク設計、リファクタリングを得意としています。そんな中、WPFアプリケーションを構造化させようと思い、WPFアプリケーションのクラスライブラリ化を試みてみました。その方法と問題点についてまとめます。

 

なぜクラスライブラリ化するのか

完全なる素人はマクロのことしか考えられず、プログラミングのアルゴリズムの世界に苦戦したり挫折したりします。一方で、プログラマーはアルゴリズムのミクロな世界に取り込まれてしまってマクロな世界が見えなくなっている人が多いことが問題になっています。これにより、

  • 複雑な依存関係
  • 再利用性の低いオブジェクト
  • 再現性の低い不具合
  • 可読性の低下

などなどの問題を発生させてしまいます。したがって、一定のプログラミング能力が身に着いたら、今度はマクロな世界に視点を向けないといけないのです。

とはいえソフトウェアは複数人で作るもの。自分の中で意識している参照関係を他のプログラマーが簡単に違反してスパゲッティ化しているなんてことは日常茶飯事です。これを少しでも防ぐために、internalやprotected、privateで参照を禁止します。更には、責務ごとにnamespaceを切り分け、別のdllとしてしまうのです。別のdllにするということは疎結合になっているとも言えます。こうやってdllとしてクラスライブラリ化することで、他のプログラマーによる参照違反を防ぎ、更に再利用性も向上させることができるわけです。

 

MVVMとnamespace

クラスライブラリは基本的にnamespace単位で作っていました。しかし、WPFのnamespaceの区切り方が良く分かりません。例えばPhoneというモジュールがあったとして、namespaceはどのように分けるのでしょうか。

  1. App.View.Phone, App.ViewModel.Phone, App.Model.Phone
  2. App.Phone.View, App.Phone.ViewModel, App.Phone.Model

分からん。しかし、1の場合はモジュールの切り分けが難しそうです。2のほうがモジュール単位になっています。というわけで、今は2を使っています。こうなると、App.Phone.dllというクラスライブラリを作りたくなってきますね。

 

さっそく作ろうとするが

f:id:hazakurakeita:20160613230437p:plain

プロジェクトを作成します。しかし、そこにクラスライブラリ(WPF)というテンプレートは存在しません。普通のクラスライブラリで良いのかなーと思って、クラスライブラリを選択してみます。

f:id:hazakurakeita:20160613230617p:plain

しかし、このテンプレートプロジェクトに追加できるWPFアイテムはユーザーコントロールのみとなっています。WindowやPageは追加できません。WindowsFormのようにFormが追加できないので、UI付きのクラスライブラリを作ることはできません。

 

WPFのクラスライブラリを作る方法

f:id:hazakurakeita:20160613231203p:plain

しょうがないのでプロジェクトテンプレートはWPFアプリケーションを選択します。

f:id:hazakurakeita:20160613230831p:plain

すると、当然ですがWindowやPageを追加することができます。

f:id:hazakurakeita:20160613231458p:plain

WPFアプリケーションはデフォルトで出力の種類がWindowsアプリケーションになっているのでクラスライブラリに変更します。これで仕様上はプロジェクトはexe形式ではなく、dll形式で出力されることになります。つまりクラスライブラリ化できるわけですね。

f:id:hazakurakeita:20160613231636p:plain

しかし、そのままではビルドに失敗します。これはApp.xamlが存在するためです。App.xamlを削除するとビルドが通るようになります。

f:id:hazakurakeita:20160613232326p:plain

WindowやPageを追加しても、

f:id:hazakurakeita:20160613232354p:plain

ビルドが通ります。WindowやPageを持つdll、クラスライブラリの完成です。

 

しかし問題が

UIを含むクラスライブラリなので、各dllに画像などのリソースも入れておきたいと考えました。しかしここで問題が発生。デザイナーでは表示されている画像が、動作環境では見つからないと例外が発生してしまうのです。ビルドも通るのですが…。

f:id:hazakurakeita:20160613232656p:plain

結局挫折。

どうもクラスライブラリ化するとリンク関係が上手く動作しないらしい。何時間も調べていたのですが、「XAMLはクラスライブラリ化を想定していない。」といった趣旨のMicrosoftのコメントを見つけました。そもそも方法も若干強引ですし、一般的にやらないことなんでしょうねー。

 

対策

f:id:hazakurakeita:20160613230617p:plain

ということで、プロジェクトテンプレートでクラスライブラリを選択し、ユーザーコントロール(WPF)のクラスライブラリ程度で済ますしかないようです。

 

おしまい。