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
Bitmap scaling issues and
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
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
But all these never seem to work in my case.
Does anyone know / suggest me a better approach to tackle this issue.
Thanks
VATSAG
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.
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.
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.
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%
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:
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With