I have a non-DPI aware WPF application where I want to draw a set of polygons in a borderless window to fit exactly on a monitor. I have an algorithm in place to scale and draw my polygons to any given resolution. In my setup I have a 4K and a FullHD monitor next to each other. My 4K monitor has its scale set to 150% and the FullHD monitor is set to 100%. For the 4K monitor, this means that if I set a windows width and height to 3840x2160, the actual rendered resolution is 2560x1440. Now if I scale my set of polygons to 4K, the polygons get rendered outside the canvas and the window. I suspect this is because the polygons are not aware of the DPI setting of my 4K monitor. If I draw the polygons on my FullHD monitor, they fit perfectly since that monitors scale is set to 100%.
To combat this problem, I have tried the following:
- Retrieve the DPI of each monitor and scale the polygons with the DPI in mind.
This works partly. Since my application is non-DPI aware (note that I am not willing to make it DPI aware since that introduces a whole new set of problems), any method for retrieving a monitors DPI results in getting 144 (150%) for both monitors. This results in the polygons fitting perfectly on my 4K monitor, but they will be scaled too small on my FullHD monitor. I have tried the following methods for retrieving DPI: GetDpiForMonitor
from Shcore.dll
, VisualTreeHelper
and Matrixes. Note that these methods do work if I set my application to be DPI aware, but I can not do that for all the extra work that introduces.
- ViewBox wrapping the Canvas
ViewBox does not automatically downscale the contents when I set the canvas width and height to 3840x2160 (ViewBox requires its contents, the canvas, to have a set width and height).
- Retrieving the "real"/scaled resolution of a monitor
With this I mean I need to access an API of some kind which will return a resolution of 2560x1440 for my 4K monitor. I have tried the classic Windows.Forms.Screen
API as well as the newer WindowsDispalyAPI. But both always return a 4K resolution for my 4K monitor.
So all my algorithms are working, I only need to find any of the following:
- A reliable way to retrieve DPI of an individual monitor while keeping my application non-DPI aware.
- A way to retrieve the scaled resolution of monitor.
- Some other way to scale a set of polygons to fit the screen.
Any help is appreciated.
Edit:
Here is an xaml exmaple of a borderless window which reproduces the problem on a 4K screen with 150% scaling:
<Window x:Class="Test.Views.FullscreenPolygon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Width="3840" Height="2160"
WindowStyle="None" AllowsTransparency="True" Background="Transparent">
<Grid>
<Canvas x:Name="CanvasArea">
<Polygon Points="2888,0 3360,2140 3840,0" Fill="Black"></Polygon>
<Polygon Points="1920,20 1450,2160 2400,2160" Fill="Black"></Polygon>
</Canvas>
</Grid>
</Window>
As you can see, both polygons (triangles) are scaled to fit the 4K resolution of the window. The window itself gets rendered as 2560x1440, because of the 150% scaling of the monitor. The polygons however, get rendered outside of it, partly onto my second screen.
Edit2:
Got it working thanks to Jeff, using the GetScreenScaleFactorNonDpiAware
method in his project.