Search code examples
c#wpfresolutiondpi

How to Change DPI Scaling behavior in C#


In our application, we have functionality that does not work properly with 4k monitors. We can get things to work correctly by changing the following settings when we right click on the executable and change the compatibility settings.

My question is: Is it possible to change these two settings highlighted in the red box from within the c# code for a WPF application? I want to execute a method, change these settings, and when the timer of 5 seconds is over, I want to change them back.

Here is how I am fetching the coordinates for the screens I am identifying.

private void btn_identifyScreens_Click(object sender, RoutedEventArgs e)
{
   int screenNumber = 1;
   foreach (System.Windows.Forms.Screen screen in System.Windows.Forms.Screen.AllScreens)
   {
       NumberSplash numberSplash = new NumberSplash(screenNumber);
       numberSplash.Left = screen.WorkingArea.Left;
       numberSplash.Top = screen.WorkingArea.Top;
       numberSplash.Width = screen.WorkingArea.Width;
       numberSplash.Height = screen.WorkingArea.Height;
       numberSplash.Show();
       screenNumber++;
   }
}

enter image description here


Solution

  • I you don't want to mess with the win32-api you can set dpi-awareness for your application in the app-manifest. For example, per monitor dpi-awareness:

    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    ...
        <application xmlns="urn:schemas-microsoft-com:asm.v3">
            <windowsSettings>
                <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
         <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
             PerMonitor   
         </dpiAwareness>
            </windowsSettings>
        </application>
    ...
    </assembly>
    

    See above on GitHub: https://github.com/Microsoft/WPF-Samples/tree/master/PerMonitorDPI

    If you want fine-grained control inside your application I belive you may have to use the win-api. There's a great article describing this here: https://blogs.windows.com/buildingapps/2017/04/04/high-dpi-scaling-improvements-desktop-applications-windows-10-creators-update/

    You can also set the registry keys directly Computer\HKEY_CURRENT_USER\Control Panel\Desktop (but this will affect all programs as Ben pointed out in the comment below) The keys are described here: https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/dpi-related-apis-and-registry-settings

    Edit: The first approach would be to make the application DPI-aware using the manifest and then if you need the application to handle dpi-changes and make it truly DPI-aware you will need to query GetDpiForMonitor (for per monitor awareness). There's a similar question with a wrapper here: How to get DPI scale for all screens?

    2:nd Edit: After the comments here is an example that displays monitor numerals on each screen: https://gitlab.com/mattincode/wpf_dpi_aware.git