Click here to Skip to main content
16,022,339 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
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.

What I have tried:

I tried a lot to get the initial DPI But I am unable to do that. I try by save the DPI X-Y coordinates in settings file in WPF but nothing works.
Posted

1 solution

By default, WPF works with device independent units. When you have problems is when you try to force it to become resolution dependent by specifying pixels, or using bitmap. If you need images, use scalable vectors. With the ability to use dynamic sizing as well, all should be good.

Anyway, to your particular issues. The first thing I notice is your app settings doesn't look quite right. You're missing an entry.
XML
<application xmlns="urn:schemas-microsoft-com:asm.v3">
  <windowsSettings>
    <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
    <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
    <longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
  </windowsSettings>
</application>
Rather than rolling your own dpi change functionality, just use the inbuilt WPF Window version. Window.DpiChanged Event (System.Windows) | Microsoft Learn[^]
 
Share this answer
 
v2
Comments
Member 15061773 28-Jul-24 9:45am    
Thank you very much sir, for having time to answer my question. I tried your solution but that does not give me any desirable result. What I actually want is to apply the DPI Scale in my app. I hope you see my above mention code in this question. Suppose my WPF app is ruining and at that moment I change the screen resolution (along with DPI) from Full HD (I develop this app in this resolution) to any other resolution like 1366*768, so what happening is my App is perfectly scaled and the UI is proportionally get bigger as expected. But the problem is when I close the app and start it again it's forget the previous scaling.

What can I do so that the app can remember the previous DPI Scaling? I tried a lot but did not find an authentic result according to my needs.

If you give me any solution then I am ready to accept your answer.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900