1

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

nikotromus
  • 1,015
  • 16
  • 36
  • Look at this: https://stackoverflow.com/questions/44398075/can-dpi-scaling-be-enabled-disabled-programmatically-on-a-per-session-basis that links to this: https://msdn.microsoft.com/en-us/library/windows/desktop/dn302122.aspx – shadowsheep Mar 01 '18 at 14:13
  • https://msdn.microsoft.com/en-us/library/system.windows.media.disabledpiawarenessattribute(v=vs.110).aspx – Hans Passant Mar 01 '18 at 14:50

1 Answers1

1

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

msrd0
  • 7,816
  • 9
  • 47
  • 82
Matt
  • 141
  • 9
  • Do NOT change `HKEY_CURRENT_USER\Control Panel\Desktop` in order to try to solve this, it will screw up all other programs on the computer. – Ben Voigt Mar 05 '18 at 21:56
  • I agree, my bad. :) – Matt Mar 06 '18 at 06:10
  • 1
    When I add that xml to my manifest file, change the true to false and delete the 'PerMonitor' string, I get my desired effect. But, the application in my 4k monitor looks ridiculous. Maybe the short answer to this issue is - "It's complicated". ;-) – nikotromus Mar 06 '18 at 14:25
  • Can you give some more details on what you are doing that looks strange on 4K monitors, is it some custom drawing? The problem with dpi-awareness is that once you set it your application assumes the responsibility to handle the scaling itself. – Matt Mar 06 '18 at 14:30
  • All I am trying to do is identify monitors by their position. Once I find the position, I throw a number on a screen so to identify which monitor it it. So, if there are 3 machines hooked up to the program, it will center and place a giant '1' on monitor 1, and giant '2' on monitor two and a giant '3' centered on monitor 3. The algorithm I'm working with works great for non 4k monitors. It is broken when you add a 4k monitor to the mix. – nikotromus Mar 06 '18 at 14:49
  • Are you using rendering the numbers using the TextFormatting-Api, RenderTargetBitmap or Images? In that case you can have a look at the samples at Github for the specific cases. For example textformatting: https://github.com/Microsoft/WPF-Samples/tree/master/PerMonitorDPI/FormattedTextExample – Matt Mar 06 '18 at 14:54
  • I forgot to ask what .NET version you are targeting.. the examples I linked to on GitHub assume .NET 4.6.2 or greater (and Win10 + perMonitor DPI-awareness... Yes it's a bit of a mess. :) – Matt Mar 06 '18 at 14:56
  • I have a xaml page with a styled textblock to show the number on the screen. I loop through all the screens deteced in System.Windows.Forms.Screen.AllScreens, test the coordinates of the screen and throw throw up the number. I'll edit my question to show you what I am doing. Also - targeting .net version 4.6.1, and I am currently using a windows 10 machine. – nikotromus Mar 06 '18 at 15:08
  • I tested the above example on a system with 2 4K monitors and one 1920x1080 and the scaling looked ok for the numbers. – Matt Mar 06 '18 at 16:22
  • @Matt Dude - thank you so much. I grafted the code into my project and it works like a charm on both 4k and non 4k monitors. I really appreciate this!!!!! – nikotromus Mar 06 '18 at 17:07
  • Glad I could help! :) – Matt Mar 06 '18 at 17:40