Making Window Size Limits DPI-Aware
A Practical Guide for DPI-Aware Window Constraints
👉 GitHub Repo: WindowSizeDemo
Let’s say that you want to set the maximum or minimum size of a window.
You might say: This is easy, just use the
OverlappedPresenter like the
WinUI Gallery example!
That’s true at first. You can set something like this:
var presenter = OverlappedPresenter.Create();
presenter.PreferredMinimumWidth = 500;
presenter.PreferredMinimumHeight = 500;
presenter.PreferredMaximumWidth = 1000;
presenter.PreferredMaximumHeight = 1000;
AppWindow.SetPresenter(presenter);
Looks perfect, until you try it on a high-DPI display or move the window between monitors.
The Problem
The properties PreferredMinimumWidth and PreferredMaximumWidth work with physical pixels, not
DPI-scaled units.
So if your app runs on a 150% or 200% scaled display, your “500px” minimum width will actually look smaller
than expected.
And if you move the window to a screen with another scale, it won’t automatically
update.
This behavior is discussed here: OverlappedPresenter resizing problem
What We Need
✅ Make the min/max sizes DPI-aware
✅ Update them when the DPI changes
dynamically
The Logic
The idea is simple:
- Get the current
DPI scale fromXamlRoot.RasterizationScale. - Multiply your width and height by that scale before applying them.
- Reapply the same logic when the DPI changes.
Example logic:
if (window.AppWindow.Presenter is OverlappedPresenter presenter &&
window.Content is FrameworkElement content &&
content.XamlRoot is not null)
{
double scale = content.XamlRoot.RasterizationScale;
presenter.PreferredMinimumWidth = (int)(500 * scale);
}
This makes your constraints consistent across different monitors and DPI levels.
🟢 For more understanding, look at the WindowSizeHelper class in the demo project.
Handling Dynamic DPI Changes
XamlRoot.Changed is raised whenever the window moves to a display with a
different scale.So you can reapply the same logic like this:
content.XamlRoot.Changed += (_, _) => ApplyWindowSizeLimits();
🟢 For more understanding, check how the event is used in MainWindow.xaml.cs.
Every time the scale changes, you just call your ApplyWindowSizeLimits()
again.
Final Thoughts
This approach is almost identical to what the WinUI Gallery uses for its own main window.
You can see
the full discussion and implementation in this PR.
Summary of Steps:
- Sizes are in physical pixels ➡ Multiply by
XamlRoot.RasterizationScale. - Sizes don’t update on DPI change ➡ Handle
XamlRoot.Changedevent. - Need clean reusable logic ➡ Move it to a helper method/class
Happy coding, and may your windows always fit just right!