How to Detect Initial DPI changes in a WPF Application while Scaling according to Per Monitor Aware in Variable Dynamic Screen Resolution?

MERUN KUMAR MAITY 531 Reputation points
2024-05-27T23:46:16.7233333+00:00

In daily life we have to deal with a lot of different types of display size it may be mobile or may be a 4k monitor. The screen resolution vary from display to display. Here another important factor is DPI (Display per inch) which is mainly a scaling factor in windows but have a great relation with screen resolution.

Now I give you an example first suppose I run the visual studio application on a Full HD monitor and the resolution is 1920x1080. Suppose I change my display resolution from full HD (1920x1080) to 1366x768. And after that I run the visual studio again on the same display and I see that the user interface (UI) is get slightly bigger and all the controls,text,icons and buttons are perfectly align according to the current monitor DPI scaling and resolution.

And the UI should get bigger as it happens when we run visual studio and other windows application on lower resolution.

I want to apply that similar effect in my WPF application so that each time the screen resolution and DPI changes, my application will automatically adjust according to the display DPI and resolution. I already try Microsoft per monitor DPI aware for windows 10 and edit the app. Mainfest file and uncomment some code according to the GitHub instructions but nothing works in my case.

I also bind with the screen resolution with my application height and width but it's cover whole the screen I don't want that.

But one thing I understand is I have to get the system DPI and disable scaling for my WPF Application even if windows has some scale per monitor or system-wide scale available.

I disabled the automatic scaling by declaring True/PM in the application manifest, which means that the application takes full responsibility for scaling, and then ignoring the WM_DPICHANGED message when it comes.

Here is the Code what I have tried :

In Application Manifest I add this code :

<application xmlns="urn:schemas-microsoft-com:asm.v3">
  <windowsSettings>
    <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
    <longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
  </windowsSettings>
</application>

Here is the Win32/C++ Base C# wrapper code :

public partial class MainWindow : Window
{
    private HwndSource hwndSource;   
    public MainWindow()
    {
        InitializeComponent();
    }
    protected override void OnSourceInitialized(EventArgs e)
    {        
        hwndSource = PresentationSource.FromVisual((Visual) sender) as HwndSource;
        hwndSource.AddHook(new HwndSourceHook(WndProc));
    }
    private const int WM_DPICHANGED = 0x02E0;
    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == WM_DPICHANGED)
        {
            handled = true;
        }
        return IntPtr.Zero;
    }
}

This Code works very much perfectly there no issue on it. And it is one of the greatest way, by using this method, application will not change scale during the lifetime. But it produce some weird issues and problems.

The problem is, it does not Detect the Initial DPI changes in a WPF Application. How Can I prevent it from scaling the application at very startup?

My Second question is, though this code works beautifully by let the application takes full responsibility for scaling itself but it unable to handle Small UI DPI changes. Pretty much Hard to understand? I give you a decent example. If somehow the Screen resolution/DPI changes, the application Main UI perfectly scale accordingly to it's own need but suppose the Application have a Combo Box and any user click the Combo Box, all we know that a drop down menu will open as it is, the catch is that, drop down menu list will not properly scale. It gives a terrible UI looks because the Main UI is scaled but Small things are not scaled up. The Tooltip Description also not scale properly. Because as we know the Tooltip only appear when I mouse hover any UI element, this hover mechanism only works after the application run initially, it does not come at first it's a some-kind of mouse mechanism.

Also, if the Application have any sub window which can be open by clicking a button after the main application run, that sub windows also not properly scale.

In a single sentence, any UI elements that are not present in the Main application User Interface (UI) at Initial Runtime are not render by the application itself.

Most important point of this question is, most of the time I call it as DPI but in practical this DPI only changes when I change the Screen Resolution, that means the DPI and the Resolution are two interconnected things. I also want to state that I just change my Laptop screen resolution from Full HD (19201080) to 1366768 to take the DPI changes effect on my WPF app.

I know in programming Universe, there multiple solutions of a single problem exists but in my case I take the solution which is easy for me to understand of my problem.

So, I take the Win32/C++ Base C# wrapper approach. If you have any other solution then you can provide me in the answer as well, If your solution works then I definitely accept your answer.

I tried some Stack Overflow code but that does not work.

Here is the Stack Overflow Question Link : https://stackoverflow.com/questions/55538032/is-there-a-way-to-disable-scaling-for-all-the-wpf-application-even-if-windows-ha

Here some other Honorable Stack Overflow Question Link Where experience developer try to discuss the answer and giving their valuable knowledge on this topic.

https://stackoverflow.com/questions/5022397/scale-an-entire-wpf-window

https://stackoverflow.com/questions/3193339/tips-on-developing-resolution-independent-application

https://stackoverflow.com/questions/13858665/disable-dpi-awareness-for-wpf-application

Windows
Windows
A family of Microsoft operating systems that run across personal computers, tablets, laptops, phones, internet of things devices, self-contained mixed reality headsets, large collaboration screens, and other devices.
4,923 questions
Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,694 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,478 questions
C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,590 questions
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

  2. Hongrui Yu-MSFT 580 Reputation points Microsoft Vendor
    2024-05-28T07:55:11.2166667+00:00

    Hi,@MERUN KUMAR MAITY. Welcome to Microsoft Q&A. 

    1.Get system DPI

    
    PresentationSource source = PresentationSource.FromVisual(this);
    
     
    
    double dpiX, dpiY;
    
    if (source != null)
    
    {
    
        dpiX = 96.0 * source.CompositionTarget.TransformToDevice.M11;
    
        dpiY = 96.0 * source.CompositionTarget.TransformToDevice.M22;
    
    }
    
    

     

    2.Disable scaling for my WPF Application

    By default, Windows Presentation Framework (WPF) cannot automatically turn on Per Monitor DPI (you can temporarily understand it as automatic scaling) to adapt to the DPI of the current screen. But when rendering a WPF program, Windows needs to stretch the program according to the DPI of the current screen to adapt it to the current screen. In the process, ambiguity and confusion arose.

     

    The code you provided does not turn off Per Monitor DPI, it turns on Per Monitor DPI. Per Monitor DPI can help your program adapt to displays with different resolutions, which is a step you should take to achieve your needs. But,Native WPF applications will DPI scale WPF hosted in other frameworks and other frameworks hosted in WPF do not automatically scale

     

    The official documentation for opening Per Monitor DPI is as follows (https://github.com/Microsoft/WPF-Samples/tree/main/PerMonitorDPI)

     

    3.For your second question, you need to use Mixed-Mode DPI Scaling (Sub-Process DPI Scaling) technology. For the use of this technology, you can refer to the official documentation (Mixed-Mode DPI Scaling and DPI-aware APIs - Win32 apps | Microsoft Learn)

     

    4.To better help you achieve your needs, you can refer to the official documentation (High DPI Desktop Application Development on Windows - Win32 apps | Microsoft Learn) If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.