[C#][.NET][WinUI 3] モダンなウィンドウを作る

WinUI 3 はモダンでいい感じではありますが、WPF を触った人からすると Window のサイズの制御はどこでするの? Microsoft 製のあのちょっとおしゃれなタイトルバーはどうやるの?といった気持ちになるかもしれません。
(というかなぁなぁで WinUI 3 に手を出した僕がそうでした。)

なので今回はちょっと今風な Window の作り方をまとめます。

このやり方はなぁなぁで触っていた僕がやっている方法なので、これより良い方法はあると思います。あくまで参考までに。

まず最初に

Win32 の API を user32.dll から引っ張ってくるマネは面倒なのでしません。
そうやらないとできないことはいったん諦めてます。(どうしてもというときだけ)
なるべくコンパクトに収まるように作ります。

開発環境

  • Windows 11 24H2 (26100.4770)
  • Visual Studio Community 2022 (17.14.8)
  • Windows App SDK (1.7.250606001)
  • WinUI 3 Gallery (2.6.0.0) … 参考資料用

学びのお供

WinUI 3 では WinUI 3 Gallery や Windows Community Toolkit Gallery といった、モダンなアプリ開発の力強いお供がいます。

今回は WinUI 3 Gallery のリンクも併せてまとめていくので、読む前に WinUI 3 Gallery をインストールしておいていください。

各項目で WinUI 3 Gallery の対象のページが開かれるリンクを置いておくので、併せて確認してみてください。

ダークテーマ・ライトテーマの対応

WinUI 3 ではデフォルトでライトテーマ・ダークテーマに対応しているので、自分で色指定しない限りは気にする必要はありません。

ありがたいですね。

ウィンドウ背景色

背景ウィンドウの後ろの要素の色がほんのり透けるようになる Mica Backdrop を使います。

WinUI 3 Gallery – System Backdrops (Mica/Acrylic) Sample

というか、2025-07-30 時点で Visual Studio 最新バージョンでの WinUI 3 プロジェクトテンプレートで最初から Mica Backdrop が使用されています。

<Window ... >

    <Window.SystemBackdrop>
        <MicaBackdrop />
    </Window.SystemBackdrop>

    ...
</Window>

ほかにもいろいろなデザインがあるので試してみてください。

汚いタイトルバーを綺麗にする

WinUI 3 のプロジェクトテンプレートを実行すると MicaBackdrop によるおしゃれな部分と古臭いタイトルバーが共存していると思います。きもいです。

自分が開発途中のプロジェクトから画像を引っ張ってきます。ちょっと内容書いてあるんですが気にしないでください。

* 実行後にウィンドウサイズを調整しています

はい。気持ち悪いですね。これを綺麗にしていきます。

ダサいタイトルバーを隠す

WinUI 3 Gallery – TitleBar Sample

WinUI 3 では上図の白い部分をなくしてコンテンツを一番上まで引き伸ばすことができます。
最小化・最大化・閉じるボタンはそのままになります。

Window のコンストラクタで下記を設定します。

// Window コンストラクタ内
ExtendsContentIntoTitleBar = true;

そうするとこんな感じ

ウィンドウのタイトルがなくなっちゃいましたけど見た目はよくなりましたね。

タイトルバーの高さを変える

ダサいタイトルバーは見えなくなりましたが、右上のボタンにカーソルを乗せると…

薄い!薄すぎる!

WinUI 3 Gallery のタイトルバーを見てみると…

はい、正方形っぽくなっていますね。ボタンの高さが高くなっています。
これにしたい!ということで、以下のコードを追記します。

// ファイル先頭
using Microsoft.UI.Windowing;

// Window コンストラクタ内
ExtendsContentIntoTitleBar = true;
AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Tall; // 追記

ウィンドウ制御の多くは AppWindow 内で行います。
そのうち、タイトルバー関連は AppWindow.TitleBar 内に集約されています。

上記コードを記述して実行すると…

いい感じですね。

タイトルバーを隠したい場合、TitleBarHeightOption.Tall ではなく TitleBarHeightOption.Collapsed にすることで丸ごと隠すことができます。最小化・最大化・閉じるボタンを自分で作りたい場合などにはこれを使ってください。

タイトルバーを自分で作る

タイトルバーの高さを高くすることはできました。

ただ、コンテンツが右上のボタンと重なりかねません。

ここはコンテンツ内で自作タイトルバーを作成してあげます。
Window の XAML ファイルを下記のようにします。

<Window ... >

    <Window.SystemBackdrop>
        <MicaBackdrop />
    </Window.SystemBackdrop>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="48"/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <StackPanel VerticalAlignment="Stretch" Margin="16,16,160,16">
            <TextBlock x:Name="TB_SettingsTitleName" Text="Settings - ClipOverlay" Style="{StaticResource CaptionTextBlockStyle}"/>
        </StackPanel>

        <Grid Grid.Row="1">
            ...
        </Grid>
    </Grid>
</Window>

AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Tall; を設定しているときのタイトルバーの Height は 48px っぽいのですが、実際は 47px にすると高さが合いそうです。どっちでもいいと思います。上記コードでは 47px にしています。 にしてください。Tallの時は縦横どちらも48pxです。DPI 125%だと最小化・最大化・閉じるボタンが47pxっぽく感じるのですが、200%にすると明らかに高さに違いがでました。48pxが正しいです。

ボタンの幅も 48px で 3 ボタンなので、48px × 3 = 144px 、StackPanel の 全方向 Margin 分 16px を加味して左上下 16px 、右 160 px にしています。
(ここらへんのサイズ情報ってどこかから取得できるんですかね🤔)

ウィンドウのコンテンツは <Grid Grid.Row="1"> の中に書きます。

いい感じですね。
オリジナルのタイトルバーは見えないだけで存在しているので、ウィンドウの移動などは赤枠の部分をドラッグすることでできます。

これを違う範囲にしたい場合、例えば「ウィンドウのどこをドラッグしてもウィンドウを動かせるようにしたい」といった場合は SetTitleBar() メソッドにタイトルバーにしたい要素を渡してあげます。

ウィンドウのサイズを制御する

WinUI 3 Gallery – AppWindow Sample

WPF では Window のデフォルトサイズや最小・最大サイズをXAML側で指定できますが、WinUI 3 ではできません。

これらを制御するには Presenter と Resize() / ResizeClient() / MoveAndResize() メソッドを使用します。

Presenter で最小・最大サイズを指定する

Window の表示周りは AppWindow.Presenter で制御します。でもこれは AppWindow.Presenter.*** = ***; で設定するのではなく、Presenter を作成して最後に Window に Set します。

Presenter には以下の 3 種類があります。

Presenter の種類内容
OverlappedPresenter一般的なウィンドウ形式
FullScreenPresenterフルスクリーン
CompactOverlayPresenterPiP (Picture in Picture) のような常に最前面で決まったサイズで表示する形式

ウィンドウの最小・最大サイズを指定できるのは OverlappedPresenter だけです(たぶん)。
最小・最大サイズを指定してWindowにセットするコードは下記のとおりです。

// Window コンストラクタ内
OverlappedPresenter presenter = OverlappedPresenter.Create();
presenter.PreferredMinimumHeight = 400; // 最小ウィンドウ高さ
presenter.PreferredMinimumWidth  = 500; // 最小ウィンドウ幅
presenter.PreferredMaximumHeight = 800; // 最大ウィンドウ高さ
presenter.PreferredMaximumWidth  = 900; // 最大ウィンドウ幅
AppWindow.SetPresenter(presenter);

最小・最大サイズはすべて指定する必要はありません。必要なものだけでOKです。

AppWindow.SetPresenter() で設定した後は、 AppWindow.PresenterOverlappedPresenter にキャストしてあげることで再取得が可能です。

が、OverlappedPresenter.Create() で作成したインスタンスを Window の Property で保持していたほうが楽です。具体的には下記。

// class property
private readonly OverlappedPresenter Presenter;

// Window コンストラクタ内
Presenter = OverlappedPresenter.Create();
Presenter.PreferredMinimumHeight = 400; // 最小ウィンドウ高さ
Presenter.PreferredMinimumWidth  = 500; // 最小ウィンドウ幅
Presenter.PreferredMaximumHeight = 800; // 最大ウィンドウ高さ
Presenter.PreferredMaximumWidth  = 900; // 最大ウィンドウ幅
AppWindow.SetPresenter(Presenter);

これでウィンドウの最大・最小サイズを制御できます。
Property として保持している Presenter の値を変更することでいつでも設定値を変更できます。

Window のデフォルトのサイズを設定する

デフォルトのサイズは Presenter ではなく AppWindow.Resize()AppWindow.ResizeClient() を使用します。
Resize と ResizeClient の違いはほかにも記事があるのでそちらを参考にして下さい。

WinUI 3での実用的なWindowサイズの設定 #C# – Qiita

基本的にはResizeClient() を使えばOKです。実際は指定したサイズより高さがちょっとだけ高くなります。(23.68px くらい。TitleBarHeightOption.Tall を設定したときだけだったり?)

大体のサイズの指定でOKならばResizeClient()で大体のサイズを指定すればOK。厳密に設定したい場合はDPI Scale周りを意識したほうがよさそうなので、他記事も参考にしてください。

おまけ 1 :Presenter でのウィンドウ設定

いろいろな設定を Presenter 経由で行えます。

プロパティ内容
Presenter.IsAlwaysOnTop常に最前面に表示するかを設定する
Presenter.IsMaximizable最大化を許可するか設定する
Presenter.IsMinimizable最小化を許可するか設定する
Presenter.IsResizableウィンドウサイズの変更を許可するか設定する

おまけ 2 :C#コードからの最大化・最小化

ウィンドウの最大化・最小化をC#コードから行うには Property として保持している Presenter を利用します。

メソッド内容
Presenter.Minimize()ウィンドウを最小化
Presenter.Maximize()ウィンドウを最大化
Presenter.Restore()最小化・最大化したウィンドウを元に戻す

全体像

XAML コード

<?xml version="1.0" encoding="utf-8"?>
<Window ... >

    <Window.SystemBackdrop>
        <MicaBackdrop />
    </Window.SystemBackdrop>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="47"/>
            <RowDefinition/>
        </Grid.RowDefinitions>


        <StackPanel VerticalAlignment="Stretch" Margin="16,16,160,16">
            <TextBlock x:Name="TB_SettingsTitleName" Text="App title here" Style="{StaticResource CaptionTextBlockStyle}"/>
        </StackPanel>

        <Grid Grid.Row="1">
            ...
        </Grid>
    </Grid>
</Window>

C# コード

using Microsoft.UI.Xaml;
using Microsoft.UI.Windowing;

public sealed partial class SettingsWindow : Window
{
    private readonly OverlappedPresenter Presenter;

    public SettingsWindow()
    {
        InitializeComponent();

        ExtendsContentIntoTitleBar = true;
        AppWindow.TitleBar.PreferredHeightOption = Microsoft.UI.Windowing.TitleBarHeightOption.Tall;

        Presenter = OverlappedPresenter.Create();
        Presenter.PreferredMinimumHeight = 400;
        Presenter.PreferredMinimumWidth = 500;
        AppWindow.SetPresenter(Presenter);

        AppWindow.ResizeClient(new(500, 400));
    }
}

これで実行するとこんな感じになります。

いい感じになりましたね。
今回はこの辺にしておきます。

投稿者 ぶどうじゅーす【公式】

多趣味な人です

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です