かずきのBlog@hatena

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

WPF on .NET Core 3.0 + XAML Islands で Windows UI Library を使おう

前回

blog.okazuki.jp

Windows UI Library を使おう

Windows UI Library(WinUI) は、次のメジャーアップデートから Windows の OS のバージョンアップに紐づいてアップデートされてきた UWP の UI 部分を OSS として切り離して開発するというポジションになるライブラリです。

今時点の v2 系は、最新の UWP コントロールを古い OS に向けてバックポートするためのライブラリって感じですが、今後は最新だろうがなんだろうか WinUI という感じになりそうです。

さて、その中のコントロールを .NET Core 3.0 の WPF で使ってみましょう。

プロジェクト作り

とりあえず前回と同じで、WPF、UWP、クラスライブラリ(UWP)のプロジェクトを作って下準備します。

下準備が終わったら Microsoft.UI.Xaml パッケージの最新のプレビュー版を UWP のプロジェクトに追加します。 追加したら App.xaml に WinUI 関連のリソースを読み込ませます。

<xaml:XamlApplication
    x:Class="UWPHost.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:xaml="using:Microsoft.Toolkit.Win32.UI.XamlHost"
    xmlns:local="using:UWPHost">
    <Application.Resources>
        <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" /> <!-- これ -->
    </Application.Resources>
</xaml:XamlApplication>

Windows UI ライブラリーの RatingControl を置いて…

<UserControl
    x:Class="WinUIControls.UwpControlsHost"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:WinUIControls"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:winui="using:Microsoft.UI.Xaml.Controls"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400">

    <Grid>
        <winui:RatingControl />
    </Grid>
</UserControl>

MainWindow.xaml にこのユーザーコントロールを置くと…

<Window x:Class="WinUIWpf.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WinUIWpf"
        xmlns:xamlhost="clr-namespace:Microsoft.Toolkit.Wpf.UI.XamlHost;assembly=Microsoft.Toolkit.Wpf.UI.XamlHost"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <StackPanel>
        <xamlhost:WindowsXamlHost InitialTypeName="WinUIControls.UwpControlsHost" />
    </StackPanel>
</Window>

アプリがクラッシュするようになりました!RatingControl を TextBox に置き換えると動くので WinUI が何か悪さをしているように見えます。 Visual Studio の出力ウィンドウにも、それらしいメッセージは出ない。

ということで直観に従って MSIX にパッケージングしてみようと思います。 Windows アプリケーション パッケージ プロジェクトを追加します。ターゲットなどは 1903 でつくります。

パッケージ対象のプロジェクトは WPF のプロジェクトです。

f:id:okazuki:20191015100251p:plain

そして、下記ドキュメントにあるとおり .NET Core 3.0 のアプリをパッケージ化するときに今のところ手動でプロジェクトファイルを書き換えないといけない部分を書き換えます。 パッケージプロジェクトの Package.appxmanifest の SplashScreen タグもドキュメントに従って書き換えます。

XAML アイランドを使用した WPF アプリでのカスタム UWP コントロールのホスト | Microsoft Docs

<uap:SplashScreen Image="Images\SplashScreen.scale-200.png" />

WPF プロジェクトファイルに以下の PropertyGroup タグを追加

<PropertyGroup>
  <AssetTargetFallback>uap10.0.18362</AssetTargetFallback>
</PropertyGroup>

パッケージプロジェクトを実行すると…

出た!

f:id:okazuki:20191015100757p:plain

でも、MSIXに固めようとするとエラー。

f:id:okazuki:20191015101429p:plain

ということでロゴやらなんやらを Package.appxmanifest の Visual Assets のページでどかっと設定しました。

f:id:okazuki:20191015101554p:plain

そうすると、無事出来ました。

f:id:okazuki:20191015101902p:plain

念のため自分が Publisher のアプリを全部消してクリーンにしてから、上のパッケージをインストールすると無事動きました。

f:id:okazuki:20191015102104p:plain

めでたしめでたし。