しっぽを追いかけて

ぐるぐるしながら考えています

Unity と猫の話題が中心   掲載内容は個人の私見であり、所属組織の見解ではありません

Xamarin でプラットフォームごとに別ファイルでリソースを XAML 定義したい

年末の Xamarin × ResourceDictionary でプラットフォームごとに配色を変えたい の続きです

前回は App.xaml に ResourceDictionary を追加し、 タグでプラットフォームごとのリソースを定義していましたが、この書き方だと見づらいし修正も煩雑になりやすいです

そこで、プラットフォームごとのリソース定義を別々の XAML ファイルに分割することを試みてみます

f:id:matatabi_ux:20150107102011p:plain

ソリューション全体はこんな感じになります

まずは App.xaml を修正

<?xml version="1.0" encoding="utf-8" ?>
<AppBase xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         x:Class="XamarinUnityInjection.App">
  <AppBase.Resources>
    <ResourceDictionary/>
  </AppBase.Resources>
</AppBase>

ResourceDictionary を空にしただけ!

次に ThemeResources-iOS.xaml を Xamarin.Forms の Forms Xaml Page として Themes フォルダを作ってそこに追加します

f:id:matatabi_ux:20150107102300p:plain

namespace XamarinUnityInjection.iOS
{
    /// <summary>
    /// iOS 用テーマリソース定義 View
    /// </summary>
    public partial class ThemeResources : ContentView
    {
        /// <summary>
        /// コンストラクタ
        /// </summary>
        public ThemeResources()
        {
            this.InitializeComponent();
        }
    }
}

ContentView を継承するように変更して、名前空間iOS 付きに変更し・・・

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamarinUnityInjection.iOS.ThemeResources">
  <ContentView.Resources>
    <ResourceDictionary>
      <x:String x:Key="HourHandColor">#FFFF8469</x:String>
      <x:String x:Key="MinuteHandColor">#FFFF461C</x:String>
      <x:String x:Key="SecondHandColor">#FFCC3816</x:String>
      <x:String x:Key="TickColor">#FF7F4234</x:String>
      <x:String x:Key="NumberColor">#FF7F230E</x:String>
    </ResourceDictionary>
  </ContentView.Resources>
</ContentView>

XAML の方はこんな感じでカラーコードを String 型で ResourceDictionary 内に記述します

同様に Windows Phone の方も ThemeResources-WinPhone.xaml を追加します

namespace XamarinUnityInjection.WinPhone
{
    /// <summary>
    /// Windows Phone 用テーマリソース定義 View
    /// </summary>
    public partial class ThemeResources : ContentView
    {
        /// <summary>
        /// コンストラクタ
        /// </summary>
        public ThemeResources()
        {
            this.InitializeComponent();
        }
    }
}

名前空間が WinPhone 付きになっているだけ

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamarinUnityInjection.WinPhone.ThemeResources">
  <ContentView.Resources>
    <ResourceDictionary>
      <x:String x:Key="HourHandColor">#FF08007F</x:String>
      <x:String x:Key="MinuteHandColor">#FF0D00CC</x:String>
      <x:String x:Key="SecondHandColor">#FF1000FF</x:String>
      <x:String x:Key="TickColor">#FF2C267F</x:String>
      <x:String x:Key="NumberColor">#FF584CFF</x:String>
    </ResourceDictionary>
  </ContentView.Resources>
</ContentView>

XAML の方は Windows Phone 用にカラーコードの値を変えます

最後に App.xaml.cs の改修

/// <summary>
/// 共通 アプリケーションクラス
/// </summary>
public partial class App : AppBase
{
    /// <summary>
    /// アプリケーションクラス参照
    /// </summary>
    public static readonly App Current;

    ~ 中略 ~

    /// <summary>
    /// メイン画面を取得します
    /// </summary>
    /// <returns>メイン画面</returns>
    public static Page GetMainPage()
    {
        // テーマリソースの読み込み
        ContentView theme = new ContentView();
        switch (Device.OS)
        {
            case TargetPlatform.iOS:
                theme = new XamarinUnityInjection.iOS.ThemeResources();
                break;

            case TargetPlatform.WinPhone:
                theme = new XamarinUnityInjection.WinPhone.ThemeResources();
                break;
        }

        // AppResources にテーマリソースを上書き・追加します
        foreach (var resource in theme.Resources)
        {
            if (App.Current.Resources.ContainsKey(resource.Key))
            {
                App.Current.Resources[resource.Key] = resource.Value;
            }
            else
            {
                App.Current.Resources.Add(resource.Key, resource.Value);
            }
        }

        return new TopPage();
    }
}

GetMainPage の内部でプラットフォームごとに ThemeResources の ContentView をインスタンス化して、AppResource の ResourceDictionary に追加するようにしました

リソースキーが重複するものは上書きするようにしています

さていつものように動作確認!

f:id:matatabi_ux:20141205080512p:plain

テーマリソースをプラットフォームごとに別ファイル定義にしてもちゃんとできましたね!