WPFでもWin11っぽいUIを作れるFluentテーマを使う（ただし.NET 9以降）

# 概要

今年春のBuildでWPFとWin UI 3の併用の方針がはっきりと打ち出されたためか、Win UI 3前提だった機能がWPFでも使えるようになってきています。（最新の体験を実装したいならWinUI、既存資産を生かすならWPF、という使い分け方針が語られていました）

その1つとして、Win11っぽいUIを作れるFluentテーマも使えるようになります。既存プロジェクトでの使い方や使うための条件について調べてみました。

# 最初に結論まとめ

.NET 9以降が必須となるようです。（.NET 8では使えません）

その条件さえ満たせば使い方はとても簡単で、次の1行をApp.xamlのResourceDictionaryへ追加するだけで行けます。

```csharp
<ResourceDictionary Source="pack://application:,,,/PresentationFramework.Fluent;component/Themes/Fluent.xaml" />
```

最初に実装された .NET 9 Preview 4時点とはパスが変わっているので、古いWeb情報などを真似ても動かない場合があるので注意です。本記事の情報は現時点（ .NET 9 RC2）のものです。

# 詳しく

Windows 11的なMSの最新のUIを作れるFluent Design System (Fluent UI)が発表されてからだいぶ経ちましたが、Windows向けはWin UI 3のみとなっていて、WPFは取り残されたままとなっていました。今年春のBuildで、かなりさらっとですが「WPFに1行足すだけで最新のUIになります」というような話が出てきまして、ついにこの状況が変わることになりました。

なったのですが、なかなか特集記事的な情報が出てきません。どうなったのかと思って調べてみたら、[.NET 9 Preview 4のリリースノートのWPFのページ](https://github.com/dotnet/core/blob/main/release-notes/9.0/preview/preview4/wpf.md)にちょっとだけ登場していました。その他のMS Learn等のページでは情報を見つけられず、かなりひっそりとした感じです。

少なくともリリース済みではあるようなので、既存のWPFプロジェクトで使えるかを試してみました。

Buildでは「1行足すだけで使える」みたいな言い方をしていた気もしますが、既存の.NET 8のWPFプロジェクトに1行足すとどうでしょうか。Windowsの対応バージョンも新しくして、「<TargetFramework>net8.0-windows10.0.26100.0</TargetFramework>」です。

足すのは次の1行です。

```csharp
<ResourceDictionary Source="pack://application:,,,/PresentationFramework.Fluent;component/Themes/Fluent.xaml" />
```

App.xamlのリソースディクショナリに足すので、次のような感じになります。

```csharp
<Application x:Class="WPFFluent.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WPFFluent"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary
                        Source="pack://application:,,,/PresentationFramework.Fluent;component/Themes/Fluent.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

```

これで実行すると、どうでしょうか。

```csharp
System.Windows.Markup.XamlParseException
HResult=0x80131501
Message='プロパティ 'System.Windows.ResourceDictionary.Source' の Set で例外がスローされました。' 行番号 '9'、行位置 '18'。
Source=PresentationFramework
スタック トレース:
場所 System.Windows.Markup.XamlReader.RewrapException(Exception e, IXamlLineInfo lineInfo, Uri baseUri)

内部例外 1:
FileNotFoundException: Could not load file or assembly 'PresentationFramework.Fluent, Culture=neutral, PublicKeyToken=null'. 指定されたファイルが見つかりません。
```

ダメでした。PresentationFramework.Fluentというアセンブリが必要なようです。こいつが.NET 9で追加されるということですかね。

しかたないので、.NET 9にしてみましょう。今度はWindowsの対応バージョンは古めにして、「<TargetFramework>net9.0-windows7.0</TargetFramework>」でいきます。プロジェクトファイルを書き換えます。

```xml
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net9.0-windows7.0</TargetFramework>
    <UseWPF>true</UseWPF>
  </PropertyGroup>

</Project>

```

これで実行すると・・・動きました！

元々の画面がこんな感じですが

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616143/f4b80259-f80c-e61f-0260-5278fd5b3a7b.png)


その1行だけで、こういう感じになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616143/e9fd59ad-0d04-c36e-e230-65f722d88677.png)


OS側をダークテーマにするとこんな感じです。ちゃんと追従しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3616143/df939a9f-d8e4-f114-69c9-3a5be714bbca.png)


## 古い情報に注意

.NET 9 Preview 4の時は、Fluent.xamlのパスが違っていました。そのため、当時のブログ記事などを参考にして次のように書いてしまうと・・・

```csharp

<ResourceDictionary Source="pack://application:,,,/PresentationFramework.Fluent;component/Resources/Fluent.xaml" />

```

こんなエラーを食らいます。

```csharp
System.Windows.Markup.XamlParseException
HResult=0x80131501
Message='プロパティ 'System.Windows.ResourceDictionary.Source' の Set で例外がスローされました。' 行番号 '8'、行位置 '18'。
Source=PresentationFramework

内部例外 1:
IOException: リソース 'resources/fluent.xaml' を検索できません。
```

うっかり古い記事を参考にして「動かない！」とかにならないように気をつけましょう。

# まとめ

既存WPFアプリでも、.NET 9にして1行足すだけでだいぶ今っぽいUIになり、ダークテーマなどにも対応できるようです。.NET 9を使えるプロジェクトではさっそく、LTS待ちでも.NET 10で取り込んでいきたいですね！