かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

ユニバーサルWindowsアプリでコード共有の方法などあれこれ

花粉がつらい今日この頃です。

Sharedプロジェクト

まずは基本です。Universal Windows appでは、SharedのプロジェクトにおいたコードはWindowsストアアプリとWindows Phone アプリで共有されます。

f:id:okazuki:20140420105417j:plain

このときXAMLもC#も共有されます

プラットフォーム固有のXAML

でも、プラットフォーム固有の処理や見た目を定義したいことがありますよね。ページはそのまま個別に作ればいいですが、リソースてきなXAMLは両方のプロジェクトに同じ名前で作成してApp.xamlで読み込みましょう。

こんな風にPlatformDictionary.xamlを両方のプロジェクトに作って…

f:id:okazuki:20140420110056j:plain

App.xamlで読み込む。これでWindows ストア アプリのときはストアのプロジェクトのやつを読み込んで、電話のときは電話のプロジェクトのやつを読み込みます。

<Application
    x:Class="App33.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App33">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="PlatformDictionary.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

コントロールのスタイルとか、DataTemplateに効果を発揮しますね。

partialクラス

ビルドしたアセンブリが共有されるのではなく、コードが共有されてビルド時によきにはからってくれるという仕組みなので、パーシャルクラスが使えます。以下のようなクラス配置で。

f:id:okazuki:20140420110608j:plain

Person.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace App33
{
    public partial class Person
    {
        public string Name { get; set; }
    }
}

WPA側Person.partial.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace App33
{
    public partial class Person
    {
        public void Greet()
        {
            Debug.WriteLine("Hello Windows phone!!");
        }
    }
}

Windows store app側Person.partial.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace App33
{
    public partial class Person
    {
        public void Greet()
        {
            Debug.WriteLine("Hello Windows store app!!");
        }
    }
}

こんな風にメソッド全体が違う場合はパーシャルクラスを使うことができます。まぁでもこの後紹介する#ifディレクティブのほうがIDE支援は強いので、そっちが使うのがいいかも?

#ifディレクティブ

WINDOWS_APP, WINDOWS_PHONE_APPという定数があるので、それで#if ~ #endifでくくることでプラットフォーム固有の処理を書けます。

partialの例を#ifディレクティブになおすとこんな感じのコードになります。

f:id:okazuki:20140420111249j:plain

黄色いマーカーで示してるところでプロジェクトを切り替えると、そっちのプロジェクトでは無効なコードがグレーアウトされます。

f:id:okazuki:20140420111436j:plain