I rarely like the size of the application windows for my Win UI 3 apps. Adjusting the size is relatively straightforward with the latest Win Apps SDK, but getting the size of the target display is not at all obvious. This tip shows how to get it, and provides an example of using it.
Introduction
So far as I can tell, getting the size of the currently active display within a Windows App SDK (aka Win UI 3) application isn't intuitively obvious. This tip shows one way of obtaining the information, and how you might use it.
Retrieving and Using Display Information
Here's a method from an app I wrote which sets the initial size of the app's window:
private async Task SizeWindow( AppWindow appWindow )
{
var displayList = await DeviceInformation.FindAllAsync
( DisplayMonitor.GetDeviceSelector() );
if( !displayList.Any() )
return;
var monitorInfo = await DisplayMonitor.FromInterfaceIdAsync( displayList[ 0 ].Id );
var winSize = new SizeInt32();
if( monitorInfo == null )
{
winSize.Width = 800;
winSize.Height = 1200;
}
else
{
winSize.Height = monitorInfo.NativeResolutionInRawPixels.Height;
winSize.Width = monitorInfo.NativeResolutionInRawPixels.Width;
var widthInInches = Convert.ToInt32( 8 * monitorInfo.RawDpiX );
var heightInInches = Convert.ToInt32( 12 * monitorInfo.RawDpiY );
winSize.Height = winSize.Height > heightInInches?
heightInInches: winSize.Height;
winSize.Width = winSize.Width > widthInInches ? widthInInches: winSize.Width;
}
appWindow.Resize( winSize );
}
I won't go through every line in the method because some of it is "belt and suspenders" logic to keep things from blowing up in unusual circumstances. But the basic logic is simple and starts by calling DeviceInformation.FindAllAsync
using a value you get by calling DisplayMonitor.GetDeviceSelector
.
DeviceInformation.FindAllAsync
, if called without an argument, appears to return information on every single device known to Windows (when I called it that way the first time, I got more than 650 items returned).
Fortunately, the call to DisplayMonitor.GetDeviceSelector
filters it down to just the display devices (on my system, which only has one display, the returned list contained only a single item).
To get the information about a display, you pass the Id
parameter of a device information object to DisplayMonitor.FromInterfaceIdAsync
.
Once that returns, the rest of the logic simply involves using the information -- assuming it was returned -- to size the application window. If the monitor info wasn't returned, I default to an 800x1200 window.
But if it was returned, I set the window to full screen and then limit it to be no more than 8 inches wide and 12 inches tall.
Once that's done, you just pass the size information to the AppWindow Resize
method.
Calling the Method
I like to size the application window in its constructor. Unfortunately, because the methods you need to call to get display information all appear to be asynchronous, I can't just call the SizeWindow
method shown above. I also need to determine the AppWindow
instance to pass to SizeWindow
.
Here's how I did that in the main window's constructor:
this.InitializeComponent();
var hWnd = WindowNative.GetWindowHandle( this );
var windowId = Win32Interop.GetWindowIdFromWindow( hWnd );
var appWindow = AppWindow.GetFromWindowId( windowId );
Task.Run( async () => await SizeWindow( appWindow ) );
There may be a more direct method for getting the AppWindow
instance because the WinUI 3/Windows App SDK is evolving rapidly. Be sure to stay on top of the changes!
Points of Interest
I was surprised that I couldn't find an easily accessible way to get the display size information. I spent well over an hour researching online before I stumbled across what I needed to put together what I've included here. Granted, that might be due to me not using the right search terms (is it a monitor or a display? and please stop giving me references to AppWindow.Resize
because I already know about it :)). If anyone knows a more direct way, I'm all ears!
History
- 3rd May, 2023: Initial post