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はアウトラインの線の分)。
簡単ですが、以上です。