特集:XAMLファミリ共通開発のすゝめ(後編)

MVVMパターンを使ったクロス・ターゲット開発

岩永 信之
2012/01/17
Page1 Page2

 前回、GUIアプリ開発において、異なるターゲット間でソース・コードを共通化できる部分と、できない部分があるという話をした。共通化できないのは、以下のような部分である。

  • UIに深くかかわる部分
  • セキュリティにかかわる部分

 この辺りを最初から意識して作れば、クロス・ターゲット開発もしやすくなるだろう。特に、XAMLファミリの場合、XAML+.NET言語(C#やVB:Visual Basic)を使って、データ・バインディングという仕組みに基づく共通の開発スタイルになっているため、アプリの大部分を共通化できる。

 今回は、具体的なサンプル・アプリ(C#)を使って、XAMLファミリ間でのクロス開発の手法を説明していこう(以下の本文中も含めて、VBのコードは割愛する)。サンプルは下記のリンク先からダウンロードできる。

 前回同様、以下のような略称を使う。

  • WPF: Windows Presentation Foundation。Windowsデスクトップ向けのGUIフレームワーク。本稿では、デスクトップ版の.NET Framework(で参照可能なライブラリ・セット)を指して「WPF」と書いている箇所もある。
  • Silverlight: 本稿で単に「Silverlight」というと、ブラウザ向けのSilverlightを指すものとする。
  • WP7: Silverlight for Windows Phone 7を指して、「WP7」という略称を使う。
  • Metro: 「Windows 8」(コードネーム)で導入されるタッチ・インターフェイス前提のGUIフレームワーク。

ソース・コード共有の方法

 Visual Studioでプロジェクトのターゲットを指定すると、ほかのターゲットからは参照できなくなってしまう。例えば、WPFをターゲットにした場合、Silverlightからは参照できない。

 しかし、ソース・コード的に見ると、ターゲットによらず全く同じよう に書ける部分は多い。最終手段としてはコピー&ペーストする手もあるが、保守可能性を考えると、ソース・コードは1つだけにしておきたい。

 現状、複数のターゲットで同じソース・コードを共通利用するには2通りの方法がある。

  • Portable化(共通バイナリを作成)
  • リンク(ソース・コードをプロジェクト間で共有)

 それぞれについて説明して行こう。

Portable化

 前回も説明したとおり、「Portable Class Library」というものを使えば、WPF、Silverlight、WP7、Metroのいずれからも参照可能なライブラリを作成できる*1

*1 ターゲット(デスクトップ版かSilverlightかなど)が異なるといっても、参照できるライブラリの種類が変わるだけで、アセンブリ(=DLLEXE:実行可能形式)の中身(=メタデータや中間言語命令)の仕様は完全互換となっている。「ターゲットが何か」という情報が属性として含まれているだけで、残りは全く同じである。
Portable Class Libraryでは、参照可能なクラスを、全てのターゲットから使える共通部分だけに限定したうえで、ターゲット属性として「.NETPortable」という情報を入れている。

 Visual Studio 2010からPortable Class Libraryを利用するには、以下の拡張機能をインストールする必要がある(前提条件としてVisual Studio 2010 SP1を事前にインストールしておく必要がある)。

 次期バージョンである「Visual Studio 11」(コードネーム)では標準で利用できる予定だ。

 もちろん、Portable Class Libraryでは、標準ライブラリのうち、どのターゲットにも含まれている基礎的なクラスしか参照できない。単純な計算や文字列処理で困ることはないが、ものによっては、ライブラリの不足を感じるだろう。例えば、ネットワーク・アクセスや画像処理などを行おうとすると、思いの外きつく感じるかもしれない。

 具体的には、後ほど、サンプル・アプリを使いながら説明する。

リンク

 ソース・コードさえ共有できればいい(=複数のアセンブリができてもいい)場合、Visual Studioのリンク機能を使う方法がある。Figure 1に示すように、[ファイルの追加]ダイアログで[リンクとして追加]を選択すればよい。

Figure 1 : [リンクとして追加]機能
この画面キャプチャは、[ソリューション エクスプローラー]でプロジェクト項目の右クリック・メニューで[追加]−[既存の項目の追加]を選択すると表示される[ファイルの追加]ダイアログ画面の一部である。

 [リンクとして追加]すると、Figure 2に示すような状態になる。

Figure 2 : リンクとして追加されたソース・コード

 これで、一方(上の図でいうと「TwitterViewModel(WPF)」プロジェクト)で行ったソース・コードの変更が、もう一方(「TwitterViewModel(Silverlight)」プロジェクト)に即座に反映されるようになる。

Project Linker

 1ファイルずつ[リンクとして追加]するのはかなり面倒な作業となる。かといって、プログラムがある程度できたところで一気に追加しようとすると、「使えると思って書いていたクラスが実はSilverlightのクラス・ライブラリにはなかった」というような勘違いに後から気付くというようなことも起こり得る。

 そこで便利なのが、「Project Linker」というVisual Studio拡張である。

 Project Linkerを使うと、Figure 3に示すように、(ソリューション内にある)プロジェクト間でソース・ファイルを自動的にリンクすることができる。

Figure 3 : Project Linkerによるリンクの自動管理の例
この例では、[ソリューション エクスプローラー]内の「TwitterViewModel(Silverlight)」プロジェクト項目の右クリック・メニューから[Add Project link]をクリックし、そこで表示された[Select Source Project]ダイアログで(プロジェクト・リンクのソースとして)「TwitterViewModel(Silverlight)」プロジェクトを選択している。この状態で[OK]ボタンを押してプロジェクト・リンクを追加した場合、「TwitterViewModel(WPF)」プロジェクトに追加したソース・ファイルが、「TwitterViewModel(Silverlight)」プロジェクトにもリンクとして自動的に追加される。

サンプル・アプリ

 もう少し具体的な説明をするためのサンプル・アプリとして、今回は、簡易的なTwitterクライアントを作成した。Figure 4に、作成したアプリのWPF版の画面キャプチャを示す。

Figure 4 : サンプル・アプリの画面キャプチャ

 これと同様のものを、SilverlightとWP7でも作成している。Metroは、「Visual Studio 11」が必要になるので今回はサンプルに含めなかったが、同様の手順でMetro版を作ることも容易だろう。

 ちなみに、Twitterクライアントの作り方は、RIAアーキテクチャ研究会での尾上氏のサンプル・アプリと、ReactiveOAuthのコードを参考にさせてもらっている。

プロジェクト構成

 このサンプル・アプリでは、Figure 5に示すようなプロジェクト構成を採っている。

Figure 5 : クロス開発用のプロジェクト構成の例

 いわゆるMVVM(Model-View-ViewModel)パターンを使っていて、

  • Modelの大部分はPortable Class Library化
  • ViewModelは、Project Linkerを使って100%ソース・コード共有
  • 残りのViewのみ、個別に作成

という構成になっている。

 MVVMパターン自体についての詳細は、「連載:WPF入門」を参照してほしい。

コード比率

 .csファイルと.xamlファイルの行数(空行、コメント行は除く)は、Figure 6に示すとおりである。

Figure 6 : ソース・コードの行数

 WPFの場合で、おおむね以下の比率となっている。

  • Portable化した部分: 約45%
  • 100%リンクしている部分: 約35%
  • 個別に書いた部分: 約20%

 個別部分は、そもそもVisual Studioが生成するテンプレートの時点で行数が多く、実際に自分で書いた部分はもっと少ない。SilverlightやWP7の行数が多いのも、そもそもテンプレートの行数が多いことに起因する。

 また、個別に書いた部分では、コピー&ペーストしたコードも多い。もう少し練って作ればリンク側(=ViewModel側)に移せた部分もあるだろう。書きやすさとの兼ね合いもあるので、ある程度は妥協している。

 ちなみに、XAMLコードに関してはリンクできない([リンクとして追加]した場合、リソースのパスが狂って正しくXAMLコードを読み込めない)ため、コピー&ペーストが唯一のソース・コード共有手段となる。

MVVMパターン

 今回作ったサンプル・アプリで、個別プロジェクトとリンク・プロジェクトの区切りが、おおむねViewとViewModelの境界になっている点は強調しておきたい。MVVMパターンを使うと、ソース・コード共有できる部分とできない部分を自然に分離しやすい。

 ただ、きっちりとしたMVVMパターンを採用する場合、標準ライブラリだけでは機能が不足していて、難しいと感じるだろう。幸い、MVVM開発を補助するためのライブラリがいくつかあり、NuGetを介して入手可能だ。今回は、MVVM Light Toolkitというライブラリを利用した。

 次節からは、Portableプロジェクト(=Portable Class Library化できる部分)、リンク・プロジェクト(=リンクでソース・コード共有できる部分)、個別プロジェクト(=個別に作る部分)それぞれについて説明していこう。


 INDEX
  特集:XAMLファミリ共通開発のすゝめ(前編)
  WINDOWS 8時代のGUI開発を考える
    1.“XAMLファミリ”/GUIフレームワークの分岐
    2.一貫性のある開発スタイル/XAMLファミリ間の差
    3.WinRT
 
  特集:XAMLファミリ共通開発のすゝめ(後編)
  MVVMパターンを使ったクロス・ターゲット開発
  1.ソース・コード共有の方法/サンプル・アプリ
    2.Portableプロジェクト/リンク・プロジェクト/個別プロジェクト


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH