single.php

C# WinUI3 でウィンドウの丸みをカスタマイズする方法

C# WinUI 3アプリを作っていく途中で、調べたことを忘録的に投稿します。今回はWinUI3プロジェクトで、通常はラウンドになっているウィンドウの四隅のスタイルをカスタマイズする方法です。

DWMでウィンドウスタイルを変更

確か、Windows Vistaの時代で導入された記憶のあるDWM(Desktop Window Manager)。

Windows11までに更新を繰り返しています。

Win32でDWMに関するAPIも公開されているので、WinUI3では、Win32を通してウィンドウのスタイルをカスタマイズできます。

例えば、次のコードのようにXamlを作成します。

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

  <Grid Name="gridMain" VerticalAlignment="Center" HorizontalAlignment="Center">
    <ToggleButton Name="ToggleCornerRound" Content="ウィンドウの四隅を角にする"  />
  </Grid>
</Window>

実行すると、こんな感じで四隅がラウンドした形状でウィンドウが表示されます。

DWMでウィンドウの形状にアクセスするには[DwmSetWindowAttribute 関数]を利用します。

表示するウィンドウに次のコードを追加します。

[DllImport("dwmapi.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE dwAttribute, ref uint pvAttribute, int cbAttribute);

public enum DWMWINDOWATTRIBUTE : uint
{
  DWMWA_NCRENDERING_ENABLED,
  DWMWA_NCRENDERING_POLICY,
  DWMWA_TRANSITIONS_FORCEDISABLED,
  DWMWA_ALLOW_NCPAINT,
  DWMWA_CAPTION_BUTTON_BOUNDS,
  DWMWA_NONCLIENT_RTL_LAYOUT,
  DWMWA_FORCE_ICONIC_REPRESENTATION,
  DWMWA_FLIP3D_POLICY,
  DWMWA_EXTENDED_FRAME_BOUNDS,
  DWMWA_HAS_ICONIC_BITMAP,
  DWMWA_DISALLOW_PEEK,
  DWMWA_EXCLUDED_FROM_PEEK,
  DWMWA_CLOAK,
  DWMWA_CLOAKED,
  DWMWA_FREEZE_REPRESENTATION,
  DWMWA_PASSIVE_UPDATE_MODE,
  DWMWA_USE_HOSTBACKDROPBRUSH,
  DWMWA_USE_IMMERSIVE_DARK_MODE = 20,
  DWMWA_WINDOW_CORNER_PREFERENCE = 33,
  DWMWA_BORDER_COLOR,
  DWMWA_CAPTION_COLOR,
  DWMWA_TEXT_COLOR,
  DWMWA_VISIBLE_FRAME_BORDER_THICKNESS,
  DWMWA_SYSTEMBACKDROP_TYPE,
  DWMWA_LAST
}

public enum DWM_WINDOW_CORNER_PREFERENCE
{
    DWMWCP_DEFAULT = 0,
    DWMWCP_DONOTROUND = 1,
    DWMWCP_ROUND = 2,
    DWMWCP_ROUNDSMALL = 3
}

public static void SetWindowCornerRadius(IntPtr hwnd, DWM_WINDOW_CORNER_PREFERENCE cornerPreference)
{
    var attribute = DWMWINDOWATTRIBUTE.DWMWA_WINDOW_CORNER_PREFERENCE;
    var preference = (uint)cornerPreference;
    DwmSetWindowAttribute(hwnd, attribute, ref preference, sizeof(uint));
}

public CornerRound()
{
  this.InitializeComponent();
  var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
  SetWindowCornerRadius(hWnd, DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_DONOTROUND);
}

このコードを実行すると、ウィンドウの四隅のラウンドが無くなり、四角形で表示されます。

表示後に切り替える場合

ウィンドウの表示後に形状を切り替えたい場合には[SetWindowPos]関数を追加します。

先ほどのXamlに2つのイベントを追加します。

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

  <Grid Name="gridMain" VerticalAlignment="Center" HorizontalAlignment="Center">
    <ToggleButton Name="ToggleCornerRound" Content="ウィンドウの四隅を角にする" Checked="ToggleCorderRound_Checked" Unchecked="ToggleCorderRound_Unchecked"/>
  </Grid>
</Window>

イベントの実装部分に次のコードと関数を1つ追加します。

[DllImport("user32.dll", SetLastError = true)]
private static extern bool SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int cx, int cy, int uFlags);

private const int SWP_NOMOVE = 0x0002;
private const int SWP_NOSIZE = 0x0001;
private const int SWP_NOZORDER = 0x0004;
private const int SWP_DRAWFRAME = 0x0020;

private void ToggleCorderRound_Checked(object sender, RoutedEventArgs e)
{
  ToggleCornerRound.Content = "ウィンドウの四隅を丸にする";
  var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);

  SetWindowCornerRadius(hWnd, DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_DONOTROUND);
  SetWindowPos(hWnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_DRAWFRAME);
}

private void ToggleCorderRound_Unchecked(object sender, RoutedEventArgs e)
{
  ToggleCornerRound.Content = "ウィンドウの四隅を角にする";
  var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);

  SetWindowCornerRadius(hWnd, DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_ROUND);
  SetWindowPos(hWnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_DRAWFRAME);
}

実行すると、こんな感じで中央のトグルボタンでウィンドウの四隅のスタイルが切り替わります。

まとめ

今回は今回はWinUI3プロジェクトで、通常はラウンドになっているウィンドウの四隅のスタイルをカスタマイズする方法について紹介しました。

WinUI3では、DWMに関するAPIの[DwmSetWindowAttribute]関数を利用してウィンドウのスタイルをカスタマイズ可能です。

WinUI 3アプリで表示したウィンドウの四隅の形状をカスタマイズしたい人の参考になれば幸いです。

スポンサーリンク

最後までご覧いただき、ありがとうございます。

コメントを残す

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