かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

ユニバーサル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