Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making an existing .NET Windows application to be DPI-aware

We have an existing windows .net application in which it uses all custom controls.

Things were fine these many days as we were just supporting the default 96 dpi resolution.

Now that we need our application to be dpi-aware. Things are going haywire when we go to next

higher resolution 120 or 144 etc.

Most common issues

  1. Bitmap scaling issues and

  2. Text cut-off

After going through these MSDN docs and existing SO questions I tried to

incorporate such a fix in vain inside my application (since all the controls used are

customized and are not dpi-aware).

Things I tried after modifying my application.manifest to enable the dpi-awareness flag and setting the AutoScaleMode to AutoScaleMode.Dpi on the main form and other forms use the AutoScaleMode as Inherit

  1. Changed the control Font inside the OnLoad event

Graphics g = this.CreateGraphics(); int dpi = int.Parse(g.DpiX.ToString());

    switch (dpi)
    {
        case 125:
            this.Font = new Font(this.Font.FontFamily, this.Font.Size * 125.0f / (float)(g.DpiX));
            Debug.WriteLine("<<---- Selected DPI Resolution :" + " 125 DPI ---->"); 
            break;
    ... so on
  1. Tried overriding the ScaleControl method to make use of different scaling factor based on DPI

But all these never seem to work in my case.

Does anyone know / suggest me a better approach to tackle this issue.

Thanks

VATSAG

like image 596
this-Me Avatar asked Nov 26 '13 06:11

this-Me


People also ask

How do I make my application DPI aware?

To make your application dpi-aware, you must cancel automatic dpi scaling, and then adjust user interface elements to scale appropriately to the system dpi.

How do I change the DPI of a specific program?

High DPI Scaling in System Settings You can find them by right-clicking on a blank part of the desktop and click Display Settings. Scroll down to Scale and layout and click Advanced Scaling Settings under the dropdown selection. You can then move the slider over to the right for Fix scaling for apps.

How do you override high DPI scaling behavior?

Select Display > Change the size of text, apps, and other items, and then adjust the slider for each monitor. Right-click the application, select Properties, select the Compatibility tab, and then select the Disable display scaling on high DPI settings check box.

How do I fix DPI scaling issues for Visual Studio 2019?

There are three options to resolve the display problem: Restart Visual Studio as a DPI-unaware process. Add a registry entry. Set your display scaling setting to 100%


1 Answers

So, I just had the same problem in one of my applications. I managed to go around it in a 2 step process, which unfortunately requires a LOT of refactoring, but after the work was done, I managed to get my application to scale on different DPI's automatically. Here's how it goes:

  1. All your forms must be set to scale using AutoScaleMode = AutoScaleMode.Font. When I did some dig-up I found out that AutoScaleMode.Dpi doesn't quite work as one would expect it to. You should also choose what your standard DPI unit will be. Say that it's 96, since that's what your application was originally designed in anyways, then you must set all your forms to use AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F). You can set these configurations from the designer view. Also, if you've created any custom controls, they should all be set to use AutoScaleMode = AsutoScaleMode.Inherit. With these two things in place, you can rest assured that .NET will do all the scaling on all your static components.

  2. Now's when it gets tricky. The thing is that the framework will maintain all your controls about the right size as long as they aren't dynamically created and placed inside the form.

So if you do something like:

var myTextBox = new TextBox();
myTextBox.Location = new System.Drawing.Point(20, 20);
myForm.Controls.Add(myTextBox);

then that text box will be placed at location (20, 20) no matter what your DPI is, hence causing it to look out of place on high DPI monitors. So the solution is to NEVER use hard coded pixel values, instead use values that scale dynamically, depending on your current DPI configuration. So, instead you may want to write something like:

var graphics = Graphics.FromHwnd(IntPtr.Zero); // This gets the graphics configuration of the current screen
var scaleX = graphics.DpiX / 96; // 96 was our standard design DPI, remember?
var scaleY = graphics.DpiY / 96;
var myTextBox = new TextBox();

myTextBox.Location = new System.Drawing.Point((int)Math.Round(20 * scaleX), (int)Math.Round(20 * scaleY));

myForm.Controls.Add(myTextBox);

That way the location at which you'll draw the control on the screen will depend on the actual DPI. And, if I may suggest, I would actually extract the scaling functionality into some sort of helper class, where you define methods to scale a value on x and on y, so you'll have a standard scaling mechanism. Note that it is also important that you scale independently on x and y, since some screens have different pixel densities on each axis.

Anyways, if you follow these two conditions, your application should look just fine independent of the screen it's displayed on.

like image 111
cgledezma Avatar answered Oct 17 '22 21:10

cgledezma