前回はNavigationPageとTabbedPageの組み合わせ問題を解決しました。

Problem

お詫び

Xamarin.Formsヒトバシラー様より、UWPが動かない原因を指摘していただきました。
謹んで記事を訂正させていただきます。

Evolve 2016でXamarin.FormsにTheme機能を追加することが発表されましたが、そのマイルストーン?として日本時間5/5の夜にXamarin.Forms.ThemesのNuGetパッケージが公開されました。
まだ、NuGetのページもありませんが、Nuget PackageManagerから入手可能です。

2016/05/06 1:57 訂正

通常、サンプルプロジェクトを使えば簡単に適用できて、「すげーー」って言えるのですが、そこはXamarinというか、他のライブラリとの動作は未検証でした。
**(ちなみに、サンプルで対象なのは、AndroidとiOSのみです。UWP、Windows 8.1、Windows Phone 8は影も形もありません)** で、Prism.Unity.FormsのUnityBootstrapperクラスを使って構築した場合、気をつけないとThemeが適用されないどころか、起動すらしなくなります

Resolution

NuGet

まずは、普通にNuGetでXamarin.Forms.Themesをgetしましょう。現在ThemeはDarkとLightの2つです。
PCLへの適用です。プレリリースを対象にしてください。

NuGet
NuGet

LightとDarkを両方追加する必要は無いです。お好みで。

App.xaml

まず、プロジェクトにApp.xamlを追加します。
続いて下記のような記述をコピーします。

1
2
3
4
5
6
<Application xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:light="clr-namespace:Xamarin.Forms.Themes;assembly=Xamarin.Forms.Theme.Light" xmlns:dark="clr-namespace:Xamarin.Forms.Themes;assembly=Xamarin.Forms.Theme.Dark" x:Class="ThemesDemo.App">
<Application.Resources>
<!--<ResourceDictionary MergedWith="light:LightThemeResources" />-->
<ResourceDictionary MergedWith="dark:DarkThemeResources" />
</Application.Resources>
</Application>

上記は、

からの抜粋です。
注意するのは、x:Classの指定です。ここは、PCLのApp.csと同じになるよう修正してください。
Application.Resources内部は、NuGetで適用した、または使用した方を残してください。

補足ですが、App.xamlのカスタムツールとビルドアクションはそのままで結構です。
また、カスタムツールがMSBuild:UpdateDesignTimeXaml、ビルドアクションが埋め込みリソースです。
ビルドアクションがPageだと動きません、というかビルドが通りません。

App.cs

この時点で、App.xamlとApp.csが結びつきましたが、このままではビルドが通りません。
修正は簡単です。

1
public partial class App : Application

partial属性を付与するだけです。
ちなみに、App.csをApp.xaml.csにする必要はないです。サンプルはそうですが不要です。

おまじない

公式ページにもありましたが、必要なアセンブリがロードされないことがあるようです。

Android、iOSごとに対応があります。
必要に応じて適用をお願いします。

App.cs (Prism.Forms.Unity使う人向け)

この時点で、無事にThemeが適用されるはずですが、Prism.Unity.Forms使いはそうも行きません。
App.csにさらに修正が必要です。
通常、Appコンストラクタ内で、UnityBootstrapperの派生クラスのインスタンスの生成、およびRunメソッドのコールをしていますが、このままでは、Themeが適用されません。
だいたい、下記のような感じだと思います。

1
2
3
4
5
public App()
{
var bootstrapper = new Bootstrapper();
bootstrapper.Run(this);
}

これを、

1
2
3
4
5
6
7
public App()
{
var bootstrapper = new Bootstrapper();
bootstrapper.Run(this);

this.InitializeComponent();
}

に修正してください。
InitializeComponentが先に来ると、フリーズします。具体的には、CreateMainPageメソッドでMainPageのResolveで止まります。
このあたり、ひょっとしたら今後の更新で対応されるかもしれませんが、今はこれで動くはずです。

実行してみる

iOS

サンプル
サンプル

一部Themeが適用されていないような気がしますが、別途修正が必要?

Android

サンプル
サンプル

UWP

Prism.Unity.Forms環境下では実行できませんでした。というか動かなくなります。もっと検証が必要かも。
簡単なサンプルを作って、UWPを動かしましたがダメです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Xamarin.Forms.Xaml.XamlParseException: Position 19:16. No Property of name StyleClass found
at Xamarin.Forms.Xaml.ApplyPropertiesVisitor.SetPropertyValue(Object xamlelement, XmlName propertyName, Object value, BindableObject rootElement, INode node, HydratationContext context, IXmlLineInfo lineInfo)
at Xamarin.Forms.Xaml.ApplyPropertiesVisitor.Visit(ValueNode node, INode parentNode)
at Xamarin.Forms.Xaml.ValueNode.Accept(IXamlNodeVisitor visitor, INode parentNode)
at Xamarin.Forms.Xaml.Eleme



at Xamarin.Forms.Xaml.ApplyPropertiesVisitor.SetPropertyValue(Object xamlelement, XmlName propertyName, Object value, BindableObject rootElement, INode node, HydratationContext context, IXmlLineInfo lineInfo)
at Xamarin.Forms.Xaml.ApplyPropertiesVisitor.Visit(ValueNode node, INode parentNode)
at Xamarin.Forms.Xaml.ValueNode.Accept(IXamlNodeVisitor visitor, INode parentNode)
at Xamarin.Forms.Xaml.ElementNode.Accept(IXamlNodeVisitor visitor, INode parentNode)
at Xamarin.Forms.Xaml.ElementNode.Accept(IXamlNodeVisitor visitor, INode parentNode)
at Xamarin.Forms.Xaml.ElementNode.Accept(IXamlNodeVisitor visitor, INode parentNode)
at Xamarin.Forms.Xaml.RootNode.Accept(IXamlNodeVisitor visitor, INode parentNode)
at Xamarin.Forms.Xaml.XamlLoader.Load(BindableObject view, String xaml)
at Xamarin.Forms.Xaml.XamlLoader.Load(BindableObject view, Type callingType)
at Xamarin.Forms.Xaml.Extensions.LoadFromXaml[TView](TView view, Type callingType)
at XFApp1.BasicPage.InitializeComponent()
at XFApp1.BasicPage..ctor()
at XFApp1.App..ctor()
at XFApp1.UWP.MainPage..ctor()
at XFApp1.UWP.XFApp1_UWP_XamlTypeInfo.XamlTypeInfoProvider.Activate_4_MainPage()
at XFApp1.UWP.XFApp1_UWP_XamlTypeInfo.XamlUserType.ActivateInstance()

こんな感じのメッセージとスタックトレースを吐いて落ちます。
StyleClassが無い、という例外です。PCLに存在していても、実行するプラットフォームに突入した時点で存在しない? 哀れUWP….

なので、簡単なサンプルを作りました。
UWPプロジェクトは以下のApp.xaml内部のRequestedThemeを削除して、Xamarin.Forms.Theme.Lightを適用した結果がこちら。

サンプル
サンプル

Conclusion

早速、レビューしましたが、プレリリースだけあって、不安定極まりないです。
UWPが見捨てられたのは、どういうわけなのか….時間が無かっただけ、と思いたい。