0
2

WinUI 3での実用的なWindowサイズの設定

Last updated at Posted at 2024-09-07

WinUI 3のWindowにはサイズを直接設定できるプロパティがないので、実行時にメソッドで変える必要があります。このためにAppWindow.Resizeを使う方法がよく説明されますが、実際にアプリを作るとなるとこれは実用的でないので、どうすればいいかという話です。

1. AppWindow.ResizeよりAppWindow.ResizeClient

AppWindow.Resizeで指定するサイズは、Windowサイズを変更する他のメソッドや関数と同じく、Non-Clientエリア(タイトルバー等)と見た目上のWindowの左右下にあるスペースを含めたサイズになります。

したがって、WindowのコンテントのUI要素にきっちり合わせたサイズにするには、Clientエリアのサイズにこれらの分の幅を加える必要がありますが、これは少々手間です。そんな計算をするぐらいなら、Clientエリアのサイズそのままで指定できるAppWindow.ResizeClientを使った方がいいです。というか、WPFでもこの機能が欲しかった。

2. サイズはモニターのDPIに合わせて調整が必要

AppWindow.ResizeClientでは(AppWindow.Resizeでも)サイズをSizeInt32で渡すことになりますが、この単位は実ピクセルです。UI要素の設定で使うDIP(Device Independent Pixel)とは違います。

一方、WinUIではWindowのコンテントのUI要素のサイズはモニターのDPIに合わせて自動調整されます。したがって、ClientエリアのサイズもモニターのDPIに合わせて手動で調整した上で渡さないと、コンテントに合わなくなってしまいます。

3. 具体例

まずモニターのDPIは、WinUIにはDPIを取得するメソッドはないので、Win32で取得することになりますが、簡単なのはGetDpiForWindow関数です。取得できる値は一つだけですが、X方向とY方向のDPIが違うケースは実用的にはないと思われるので、十分でしょう。DPIそのままより96を基準としたスケール(倍数)にした方が使いやすいので、こんな感じです。

using System.Runtime.InteropServices;
using Microsoft.UI.Xaml;

internal static class WindowHelper
{
    [DllImport("User32.dll")]
    private static extern int GetDpiForWindow(nint hwnd);

    public const double DefaultPixelsPerInch = 96D;

    public static double GetWindowDpiScale(Window window)
    {
        nint windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(window);
        return GetDpiForWindow(windowHandle) / DefaultPixelsPerInch;
    }
}

次にClientエリアのサイズは、UI要素と同じ場所で設定した方が一覧性が高いので、XAMLに書くことにして、UI要素のルートになるGrid(名前をRootGridとする)で指定します。

<?xml version="1.0" encoding="utf-8"?>
<Window
    x:Class="WinuiSample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Grid x:Name="RootGrid"
          Width="400" Height="300"
          Background="#EEEEEE">
        <Grid Width="360" Height="80" Background="Red">
            <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"
                       Foreground="White"
                       FontSize="40" FontWeight="Black"
                       Text="Sample"/>
        </Grid>
    </Grid>
</Window>

その上でWindowのコンストラクターでAppWindow.ResizeClientを実行します。

using Microsoft.UI.Xaml;
using Windows.Graphics;

public sealed partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();

        double dpiScale = WindowHelper.GetWindowDpiScale(this);
        AppWindow.ResizeClient(new SizeInt32(
            (int)(RootGrid.Width * dpiScale),
            (int)(RootGrid.Height * dpiScale)));
    }
}

これで以下のようなWindowになります。DPIは175%なので、実ピクセルでは幅400×1.75+2=702です(2はアウトラインの線の分)。

WindowSample

簡単ですが、以上です。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2