tmytのらくがき

個人の日記レベルです

せっかくなのでUno Platformの話がしたい

Uno Platformというものがある

UWPのコードをベースにして、自力でXAMLを解釈して、Xamarinの上でViewをいい感じに動かすっていうアプローチ。Xamarin.Formsのラッパーではない。

俺たちが期待してるUniversalはこれなんだよ、いいからMSは早く買収するんだ。という気持ちを抑えながら、公式ページで図解されている構造を見てみるとこういう感じ。

https://s3.amazonaws.com/uno-website-assets/wp-content/uploads/2019/08/21141002/diagram.png

あれこれなんか4年前に似たような図を描いたような気がする*1

簡単なコードなら普通に動くし、複雑なコードもUno Platformをターゲットに最初から作ればわりかしちゃんと動く。よくできている。

実際にWindows 10の電卓が移植されていて、Play StoreとかApp Storeからダウンロードできるので、とりあえず「すげーーー」って言うには電卓を入れるのがおすすめ。

Uno Calculator

Uno Calculator

  • nventive
  • 仕事効率化
  • 無料
apps.apple.com play.google.com

ただ、本物のUWPと、UWPに似せたAPIを提供したXamarinだとどうしても違うことがあるので現行のUWPのコードを突っ込めばそのまま動くか?と聞かれれば答えは”ほぼNo”という感じ。 実際にコピペしたら全然動かんかった。

implicit styleが動かんという話

さて、いろいろ動かないことはあるんだけども一番困ったimplicit styleが動かんというトピックを紹介しておきます。 アプリの見た目をそろえるときにこういう書き方をすることがあります。

<Application
    x:Class="UnoApp2.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Application.Resources>
    <Style TargetType="TextBlock">
      <Setter Property="Foreground" Value="Red" />
    </Style>
  </Application.Resources>
</Application>

すべてのTextBlock の文字色が赤になることを期待しています。当然UWPで実行すると赤で表示されます。

f:id:tmyt:20191130044459p:plain

ところが、Uno Platformでビルドすると次のメッセージが得られます。

Error reading response 1>MSBUILD : error : Generation failed: System.AggregateException: 1 つ以上のエラーが発生しました。 ---> System.InvalidOperationException: Generation failed for Uno.UI.SourceGenerators.XamlGenerator.XamlCodeGenerator. System.AggregateException: 1 つ以上のエラーが発生しました。 ---> System.Exception: Processing failed for file ***\UnoApp2.Shared\App.xaml ---> System.Exception: Implicit styles in inline resources are not supported (Application, Line 1:2) 1>MSBUILD : error : 場所 Uno.UI.SourceGenerators.XamlGenerator.XamlFileGenerator.RegisterResources(XamlObjectDefinition topLevelControl) 1>MSBUILD : error : 場所 Uno.UI.SourceGenerators.XamlGenerator.XamlFileGenerator.BuildApplicationInitializerBody(IndentedStringBuilder writer, XamlObjectDefinition topLevelControl) 1>MSBUILD : error : 場所 Uno.UI.SourceGenerators.XamlGenerator.XamlFileGenerator.InnerGenerateFile() 1>MSBUILD : error : 場所 Uno.UI.SourceGenerators.XamlGenerator.XamlFileGenerator.GenerateFile()

なんやかんや書いてますが、要するにx:Key が指定されていない暗黙的なリソースはサポートされてないですよ。ということらしいのです。めっちゃ困る。

これに関連したIssue(というかPR)をGitHubで探すとこれが見つかります。

github.com

ここの、 What is current behavior? に書いてあるのですが

Uno only supports global-level resources, including implicit styles

らしいのです。このglobal-levelがポイントです。

解決する話

先のPRから現状の実装ではglobal-levelならimplicit stylesが動く。と読み取れます。 じゃぁglobal-levelなstyleとはなんぞや。という話があり、ドキュメントなどから雰囲気をつかむと要するにこれです。

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Style TargetType="TextBlock">
    <Setter Property="Foreground" Value="Red" />
  </Style>
</ResourceDictionary>

てきとうにXAMLを作って、ResourceDictionaryを書いて、その中ならimplicit styleと呼ばれているものを書きまくってもいいということらしいのです。実際動かすと動きます。

f:id:tmyt:20191130045520p:plain:w220 f:id:tmyt:20191130045903p:plain:w220

そんじゃこれ、UWPで動くんかというと動きません。実行結果はこれです。

f:id:tmyt:20191130044539p:plain

ではこれが、全部の環境で期待値となるXAMLはどうなるか。というと、App.xamlでResourceDictionaryとして読めばいい。

<!-- Themes/ImplicitStyles.xaml -->
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Style TargetType="TextBlock">
        <Setter Property="Foreground" Value="Red" />
    </Style>
</ResourceDictionary>

<!-- App.xaml -->
<Application
    x:Class="UnoApp2.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Application.Resources>
    <ResourceDictionary Source="Themes/ImplicitStyles.xaml" />
  </Application.Resources>
</Application>

これで最初の画像と同じ結果が得られます(見た目変らないので画像省略)。

だんだん奇妙なXAMLになってきましたね。さすがはCross Platform…たまんないですね…