タイトルバーをカスタマイズする - WinUI

WinUI 3 (Windows App SDK 1.1)アプリケーションで、タイトルバーをカスタマイズする手順を紹介します。

概要

こちらの記事では、タイトルバーの色を変更する方法を紹介しました。 アプリケーションによってはタイトルバーにコントロールを配置したり、独自のデザインのタイトルバーを作成したい場合があります。 この記事では、WinUI 3 (Windows App SDK 1.1)アプリケーションでタイトルバーをカスタマイズする手順を紹介します。

実装方針

Microsoft.UI.Windowing.AppWindowTitleBar オブジェクトの ExtendsContentIntoTitleBar プロパティを trueに設定します。
ExtendsContentIntoTitleBarプロパティがtrueに設定されると、キャプションやアイコン描画がされない状態になり、アプリケーションのタイトルバーを含めて ウィンドウデザインできる範囲になります。
ウィンドウ右上の、最大化、最小化、閉じるボタン、ウィンドウ左上をクリックした際に表示されるポップアップメニュー、ウィンドウタイトルバーを ドラッグした際の移動処理はシステムで表示、動作を受け持ちます。

タイトルバーの外観は、XAMLのウィンドウデザインでタイトルバーも含めたウィンドウをデザインして表示します。

なお、タイトルバーをカスタマイズできるのはWindows 11以降のOSのため、 Microsoft.UI.Windowing.AppWindowTitleBar オブジェクトの IsCustomizationSupported() メソッドでタイトルバーのカスタマイズができるかを確認したうえで、

プログラム

WinUI3アプリケーションを作成します。

コード

MainWindow.xaml
<Window
    x:Class="TitleBarCustomize.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:TitleBarCustomize"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition Height="auto"/>
      <RowDefinition />
    </Grid.RowDefinitions>


    <Grid x:Name="AppTitleBar" Height="32" Grid.Column ="0" Grid.Row ="0">
      <Grid.ColumnDefinitions>
        <ColumnDefinition x:Name="LeftPaddingColumn" Width="0"/>
        <ColumnDefinition/>
        <ColumnDefinition x:Name="RightPaddingColumn" Width="0"/>
      </Grid.ColumnDefinitions>
      <Border Grid.Column ="1" Background="#1f3d7a"/>
      <Image x:Name="TitleBarIcon" Source="/Assets/StoreLogo.png" Grid.Column="1" HorizontalAlignment="Left"
             Width="16" Height="16" Margin="8,0,0,0"/>
      
      <TextBlock x:Name="TitleTextBlock" Text="アプリケーションのタイトル" 
                 Style="{StaticResource CaptionTextBlockStyle}"
                 Grid.Column="1" VerticalAlignment="Center" Margin="28,0,0,0"/>
    </Grid>

    <Border Grid.Column ="0" Grid.Row ="1" Background="#A0A0A0"/>
    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="0" Grid.Row="1">
      <Button x:Name="myButton" Click="myButton_Click">Click Me</Button>
    </StackPanel>

  </Grid>

</Window>
MainWindow.xaml.cs
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
//using Microsoft.UI.Windowing;
//using Windows.UI.WindowManagement;

// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.

namespace TitleBarCustomize
{
  /// <summary>
  /// An empty window that can be used on its own or navigated to within a Frame.
  /// </summary>
  public sealed partial class MainWindow : Window
  {
    public MainWindow()
    {
      this.InitializeComponent();

      IntPtr hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
      Microsoft.UI.WindowId windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hwnd);
      Microsoft.UI.Windowing.AppWindow appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);
   
      if (Microsoft.UI.Windowing.AppWindowTitleBar.IsCustomizationSupported() == true) {

        appWindow.TitleBar.ExtendsContentIntoTitleBar = true;
        appWindow.TitleBar.ButtonForegroundColor = Windows.UI.Color.FromArgb(255, 20, 20, 20);
        appWindow.TitleBar.ButtonBackgroundColor = Windows.UI.Color.FromArgb(255, 168, 168, 20);
        appWindow.TitleBar.ButtonHoverForegroundColor = Windows.UI.Color.FromArgb(255, 240, 240, 240);
        appWindow.TitleBar.ButtonHoverBackgroundColor = Windows.UI.Color.FromArgb(255, 240, 200, 80);
        appWindow.TitleBar.ButtonPressedForegroundColor = Windows.UI.Color.FromArgb(255, 255, 0, 0);
        appWindow.TitleBar.ButtonPressedBackgroundColor = Windows.UI.Color.FromArgb(255, 254, 220, 120);

        appWindow.TitleBar.ButtonInactiveForegroundColor = Windows.UI.Color.FromArgb(255, 60, 60, 60);
        appWindow.TitleBar.ButtonInactiveBackgroundColor = Windows.UI.Color.FromArgb(255, 168, 20, 168);
      }
    }

    private void myButton_Click(object sender, RoutedEventArgs e)
    {
      myButton.Content = "Clicked";
    }
  }
}

解説

MainWindow.xaml

今回はウィンドウ全体をGridタグで囲み、グリッドレイアウトとして実装します。
グリッドの列は1列とします。
    <Grid.ColumnDefinitions>
      <ColumnDefinition/>
    </Grid.ColumnDefinitions>

グリッドの行は2行とします。1行目がタイトルバーの行で、2行目がウィンドウコンテンツ領域とします。タイトルバーの行は Height属性をautoに設定します。
    <Grid.RowDefinitions>
      <RowDefinition Height="auto"/>
      <RowDefinition />
    </Grid.RowDefinitions>



上のグリッドには以下のコンテンツを設定します。グリッドを入れ子にしており、3列1行のグリッドを配置しています。
3列のうち一番右と左の列は幅を0に設定しています。これは、タイトルバーの場合、キャプションボタン用に予約されている領域のため、 作成しておく必要があります。

中央の列にタイトル場のコンテンツやデザインを設定します。今回は、左側にアプリケーションのアイコンを配置し、 その右側にタイトルバーのキャプション文字列を表示しています。
Borderタグを記述して背景色を設定しています。
    <Grid x:Name="AppTitleBar" Height="32" Grid.Column ="0" Grid.Row ="0">
      <Grid.ColumnDefinitions>
        <ColumnDefinition x:Name="LeftPaddingColumn" Width="0"/>
        <ColumnDefinition/>
        <ColumnDefinition x:Name="RightPaddingColumn" Width="0"/>
      </Grid.ColumnDefinitions>
      <Border Grid.Column ="1" Background="#1f3d7a"/>
      <Image x:Name="TitleBarIcon" Source="/Assets/StoreLogo.png" Grid.Column="1" HorizontalAlignment="Left" Width="16" Height="16" Margin="8,0,0,0"/>
      <TextBlock x:Name="TitleTextBlock" Text="アプリケーションのタイトル" 
                 Style="{StaticResource CaptionTextBlockStyle}"
                 Grid.Column="1" VerticalAlignment="Center" Margin="28,0,0,0"/>
    </Grid>


下側のグリッドには、StackPanel を配置しボタンを1つ設置しています。Borderタグを記述して背景色を設定しています。
    <Border Grid.Column ="0" Grid.Row ="1" Background="#A0A0A0"/>
    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="0" Grid.Row="1">
      <Button x:Name="myButton" Click="myButton_Click">Click Me</Button>
    </StackPanel>

MainWindow.xaml.cs

はじめに、Microsoft.UI.Windowing.AppWindow オブジェクトを取得します。
その後、Microsoft.UI.Windowing.AppWindowTitleBar.IsCustomizationSupported() メソッドを呼び出しタイトルバーのカスタマイズが 可能かチェックし、カスタマイズが可能であれば、ExtendsContentIntoTitleBar プロパティを true に設定します。
以降は、ButtonForegroundColor をはじめとする、コントロールボタンのカラープロパティを設定し、ウィンドウのコントロールボタンをカスタマイズします。~
    public MainWindow()
    {
      this.InitializeComponent();

      IntPtr hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
      Microsoft.UI.WindowId windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hwnd);
      Microsoft.UI.Windowing.AppWindow appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);
   
      if (Microsoft.UI.Windowing.AppWindowTitleBar.IsCustomizationSupported() == true) {

        appWindow.TitleBar.ExtendsContentIntoTitleBar = true;
        appWindow.TitleBar.ButtonForegroundColor = Windows.UI.Color.FromArgb(255, 20, 20, 20);
        appWindow.TitleBar.ButtonBackgroundColor = Windows.UI.Color.FromArgb(255, 168, 168, 20);
        appWindow.TitleBar.ButtonHoverForegroundColor = Windows.UI.Color.FromArgb(255, 240, 240, 240);
        appWindow.TitleBar.ButtonHoverBackgroundColor = Windows.UI.Color.FromArgb(255, 240, 200, 80);
        appWindow.TitleBar.ButtonPressedForegroundColor = Windows.UI.Color.FromArgb(255, 255, 0, 0);
        appWindow.TitleBar.ButtonPressedBackgroundColor = Windows.UI.Color.FromArgb(255, 254, 220, 120);

        appWindow.TitleBar.ButtonInactiveForegroundColor = Windows.UI.Color.FromArgb(255, 60, 60, 60);
        appWindow.TitleBar.ButtonInactiveBackgroundColor = Windows.UI.Color.FromArgb(255, 168, 20, 168);
      }
    }

実行結果

プロジェクトを実行します。下図のウィンドウが表示されます。


ウィンドウが非アクティブになると、下図の表示になります。ButtonInactiveBackgroundColor で設定した色が反映されています。


ウィンドウ右上のボタンにマウスオーバーした際の表示です。ButtonHoverBackgroundColor で設定した色が反映されています。


ボタン左上のアイコン部分をクリックすると、下図のポップアップメニューが表示されます。


タイトルバーをカスタマイズできました。
著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2022-08-12
作成日: 2022-08-12
iPentec all rights reserverd.