Creating a DPI-enabled application

I have a form application in C #. When I change the DPI monitor, all the controls move. I used the code this.AutoScaleMode = AutoScaleMode.Dpi , but this did not this.AutoScaleMode = AutoScaleMode.Dpi problem.

Does anyone have any ideas?

+65
c # dpi dpi-aware
Nov 02 '10 at 7:56
source share
8 answers

EDIT: With .NET 4.7, window forms have improved support for High DPI. For more information, see docs.microsoft.com. It works only for Windows 10 Creators Update and higher, so it may not be practical to use this, but depending on your user base.




Difficult, but not impossible. Your best bet is to switch to WPF, but that might not be possible.

I spent a lot of time on this problem. Here are a few rules / guidelines to get it working correctly without a FlowLayoutPanel or TableLayoutPanel:

  • Always edit / create your default apps with 96 DPI (100%). If you create in 120DPI (125% f.ex), it will be very bad when you return to 96 DPI to work with it later.
  • I have successfully used AutoScaleMode.Font, I have not tried AutoScaleMode.DPI a lot.
  • Make sure you use the default font size for all of your containers (forms, panels, tabs, user controls, etc.). 8.25 pixels Preferably, it should not be installed in the.Designer.cs file for all containers in general, so that it uses the default font from the container class.
  • All containers must use the same AutoScaleMode
  • Make sure all containers have the following line in the Designer.cs file:

this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);//for design in 96 DPI

  • If you need to set different font sizes for shortcuts / text fields, etc., Set them for each control instead of setting the font in the container class, because winforms uses the container font setting to scale the content and has a f.ex panel with a different size font than its containing form is guaranteed. This may work if the form and all containers in the form use the same font size, but I have not tried.
  • Use another machine or a virtual Windows installation (VMware, Virtual PC, VirtualBox) with a higher DPI setting to immediately test your design. Just run the compiled.exe file from the / bin / Debug folder on the DEV machine.

I guarantee that if you follow these recommendations, you will be fine, even if you placed controls with specific anchors and do not use the flow panel. We have an application built in this way, deployed on hundreds of machines with different DPI settings, and we no longer have any complaints. All forms / containers / grids / buttons / text box etc. Dimensions scale correctly, as does the font. Images also work, but they tend to be slightly pixelated at high DPI.

EDIT: this link contains a lot of useful information, especially if you decide to use AutoScaleMode.DPI: https://stackoverflow.com/a/4648/

+103
Nov 02 2018-10-11T00:
source share
— -

Finally, I found a solution to the problem of both screen orientation and DPI processing.
Microsoft has already provided a document explaining it, but with a slight flaw that will completely destroy DPI processing. Just follow the solution in the document below in the section “Creating a separate layout code for each orientation” http://msdn.microsoft.com/en-us/library/ms838174.aspx

Then the IMPORTANT part! Inside the code for the Landscape () and Portrait () methods at the very end of each, add these lines:

 this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; 

So, the code for these two methods will look like this:

 protected void Portrait() { this.SuspendLayout(); this.crawlTime.Location = new System.Drawing.Point(88, 216); this.crawlTime.Size = new System.Drawing.Size(136, 16); this.crawlTimeLabel.Location = new System.Drawing.Point(10, 216); this.crawlTimeLabel.Size = new System.Drawing.Size(64, 16); this.crawlStartTime.Location = new System.Drawing.Point(88, 200); this.crawlStartTime.Size = new System.Drawing.Size(136, 16); this.crawlStartedLabel.Location = new System.Drawing.Point(10, 200); this.crawlStartedLabel.Size = new System.Drawing.Size(64, 16); this.light1.Location = new System.Drawing.Point(208, 66); this.light1.Size = new System.Drawing.Size(16, 16); this.light0.Location = new System.Drawing.Point(192, 66); this.light0.Size = new System.Drawing.Size(16, 16); this.linkCount.Location = new System.Drawing.Point(88, 182); this.linkCount.Size = new System.Drawing.Size(136, 16); this.linkCountLabel.Location = new System.Drawing.Point(10, 182); this.linkCountLabel.Size = new System.Drawing.Size(64, 16); this.currentPageBox.Location = new System.Drawing.Point(10, 84); this.currentPageBox.Size = new System.Drawing.Size(214, 90); this.currentPageLabel.Location = new System.Drawing.Point(10, 68); this.currentPageLabel.Size = new System.Drawing.Size(100, 16); this.addressLabel.Location = new System.Drawing.Point(10, 4); this.addressLabel.Size = new System.Drawing.Size(214, 16); this.noProxyCheck.Location = new System.Drawing.Point(10, 48); this.noProxyCheck.Size = new System.Drawing.Size(214, 20); this.startButton.Location = new System.Drawing.Point(8, 240); this.startButton.Size = new System.Drawing.Size(216, 20); this.addressBox.Location = new System.Drawing.Point(10, 24); this.addressBox.Size = new System.Drawing.Size(214, 22); //note! USING JUST AUTOSCALEMODE WILL NOT SOLVE ISSUE. MUST USE BOTH! this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); //IMPORTANT this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; //IMPORTANT this.ResumeLayout(false); } protected void Landscape() { this.SuspendLayout(); this.crawlTime.Location = new System.Drawing.Point(216, 136); this.crawlTime.Size = new System.Drawing.Size(96, 16); this.crawlTimeLabel.Location = new System.Drawing.Point(160, 136); this.crawlTimeLabel.Size = new System.Drawing.Size(48, 16); this.crawlStartTime.Location = new System.Drawing.Point(64, 120); this.crawlStartTime.Size = new System.Drawing.Size(248, 16); this.crawlStartedLabel.Location = new System.Drawing.Point(8, 120); this.crawlStartedLabel.Size = new System.Drawing.Size(48, 16); this.light1.Location = new System.Drawing.Point(296, 48); this.light1.Size = new System.Drawing.Size(16, 16); this.light0.Location = new System.Drawing.Point(280, 48); this.light0.Size = new System.Drawing.Size(16, 16); this.linkCount.Location = new System.Drawing.Point(80, 136); this.linkCount.Size = new System.Drawing.Size(72, 16); this.linkCountLabel.Location = new System.Drawing.Point(8, 136); this.linkCountLabel.Size = new System.Drawing.Size(64, 16); this.currentPageBox.Location = new System.Drawing.Point(10, 64); this.currentPageBox.Size = new System.Drawing.Size(302, 48); this.currentPageLabel.Location = new System.Drawing.Point(10, 48); this.currentPageLabel.Size = new System.Drawing.Size(100, 16); this.addressLabel.Location = new System.Drawing.Point(10, 4); this.addressLabel.Size = new System.Drawing.Size(50, 16); this.noProxyCheck.Location = new System.Drawing.Point(168, 16); this.noProxyCheck.Size = new System.Drawing.Size(152, 24); this.startButton.Location = new System.Drawing.Point(8, 160); this.startButton.Size = new System.Drawing.Size(304, 20); this.addressBox.Location = new System.Drawing.Point(10, 20); this.addressBox.Size = new System.Drawing.Size(150, 22); //note! USING JUST AUTOSCALEMODE WILL NOT SOLVE ISSUE. MUST USE BOTH! this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); //IMPORTANT this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; //IMPORTANT this.ResumeLayout(false); } 

Works like a charm for me.

+14
Apr 12 2018-12-12T00:
source share

Note: this will not fix the movement of controls when dpi changes. this will only fix the blurry text !!.




How to fix blurry Windows Forms in high resolution settings:

  1. Go to the form designer, then select the form (by clicking on the title bar)
  2. Press F4 to open the properties window,
  3. then find the AutoScaleMode property
  4. Change it from Font (default) to Dpi .

Now go to Program.cs (or to the file where your Main method is located) and change it like this:

 namespace myApplication { static class Program { [STAThread] static void Main() { // ***this line is added*** if (Environment.OSVersion.Version.Major >= 6) SetProcessDPIAware(); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainForm()); } // ***also dllimport of that function*** [System.Runtime.InteropServices.DllImport("user32.dll")] private static extern bool SetProcessDPIAware(); } } 

Save and compile. Your shape should now look crispy again.




source: http://crsouza.com/2015/04/13/how-to-fix-blurry-windows-forms-windows-in-high-dpi-settings/

+9
Aug 29 '18 at 9:57
source share

This seems to be a problem with Windows. Taking out these two lines, everything was fixed.

 this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 

This is where I got the solution:

+4
Mar 30 '17 at 19:31
source share

In Windows Forms, it’s really difficult to create DPI-enabled applications. You will need to use layout layouts that will correctly change when the DPI changes (for example, TableLayoutPanel or FlowLayoutPanel). All controls also need to be resized. The configuration of these containers can be a problem.

For simple applications, this can be done in a reasonable amount of time, but for large applications this is really a lot of work.

+3
Nov 02 '10 at 8:08
source share

From experience:

  • do not use DPI information with window shapes unless critical
  • for this purpose, always set the AutoScaleMode property to None for all forms and user controls in your application.
  • Result: WYSIWYG interface type when changing DPI settings
+2
Nov 02. 2018-10-11T00:
source share
  • If you want your WinForms application to be a DPI-Aware application, in addition to Trygve's good answer. If you have a large project, you can automatically scale your forms and their contents, you can do this by creating the ScaleByDPI function:

The ScaleByDPI function will receive the Control parameter, which is usually a form, and not recursively iterating through all the auxiliary controls (if (control.HasChildren == true)), as well as the location and scale sizes from your application controls, as well as font sizes and sizes to the configured DPI OS. You can try to implement it also for images, icons and graphics.

Special notes for the ScaleByDPI function:

but. For all controls with default font sizes, you need to set their Font.Size to 8.25.

b. You can get the values ​​of devicePixelRatioX and devicePixelRatioY (control.CreateGraphics (). DpiX / 96) and (control.CreateGraphics (). DpiY / 96).

from. You will need the scale of Control.Size and Control.Location using an algorithm based on control.Dock and control.Anchor. It should be noted that control.Dock can have 1 out of 6 possible values ​​and that control.Anchor can have 1 out of 16 possible values.

e. this algorithm will have the specified values ​​for the following variables bool isDoSizeWidth, isDoSizeHeight, isDoLocationX, isDoLocationY, isDoRefactorSizeWidth, isDoRefactorSizeHeight, isDoRefactorLocationX, isDoRefactorLocationY, isDoClacLocationXBasedOnRightYomDoClient.

e. If your project uses a control library other than Microsoft, special treatment may be required for this control.

Further information on the above (d.) Bool variables:

* Sometimes a group of controls (may be buttons) must be placed one after another on the same vertical line, and their Anchor value includes the right, but not the left, or they need to be placed one after the other on the same horizontal line, and their Anchor value includes Bottom, but not Top, in which case you need to recalculate the controls. Location values.

* In the case of controls in which Anchor contains top and bottom and / or left and right, you will need to change the settings for the Size and Location controls.

Using the ScaleByDPI function:

but. Add the following command at the end of any form constructor: ScaleByDPI (this);

b. Also, when dynamically adding a control to the form call ScaleByDPI ([ControlName]).

  1. When you set the size or location of any control dynamically after the constructor completes, create and use one of the following functions to get scaled values ​​for the size or location: ScaleByDPI_X \ ScaleByDPI_Y \ ScaleByDPI_Size \ ScaleByDPI_Point

  2. To mark your application as a DPI tool, add the dpiAware element to the application build manifest.

  3. Set GraphicsUnit for all Control.Font in System.Drawing.GraphicsUnit.Point

  4. In the * .Designer.cs files of all containers, set the AutoScaleMode value to System.Windows.Forms.AutoScaleMode.None

  5. in controls such as ComboBox and TextBox, the Control.Size.Hieght change is not affected. In this case, a change to Control.Font.Size will determine the height of the control.

  6. If the StartPosition form is set to FormStartPosition.CenterScreen, you will need to recount the window location.

+1
Mar 09 '15 at 9:17
source share

Since the Winform application form may contain content controls and images, which allows you to resize your YOUR window, it is NOT a solution, but if you could have one form in DPI resolution, with properly scaled images ... And this is not a good idea, so as with increasing screen size, the font size decreases.

When using a different DPI resolution, the system forces your form to redefine its size, location and control font, BUT NOT IMAGES, the solution is to change the DPI shape at runtime, at startup, so that everything returns to its original size and location.

This is a possible solution that I tested with the application for card games, where I have 80 image buttons, TabControls, etc.

In each form_Load event of the form, add this piece of code:

  Dim dpi As Graphics = Me.CreateGraphics Select Case dpi.DpiX Case 120 '-- Do nothing if your app has been desigbned with 120 dpi 
  Case Else '-- I use 125 AND NOT 120 because 120 is 25% more than 96 Me.Font = New Font(Me.Font.FontFamily, Me.Font.Size * 125 / dpi.DpiX) End Select 

In addition, a quick trick to test various resolutions on the same computer without restarting:

From the control panel, change the resolution. Do not restart! Instead, close the session and open a new one with the same user.

There is another caveat: if you set the size and position of the control at run time, then you should apply the same DPI factor (for example, 125 / Dpi.Dpix) to the new coordinates. Therefore, you better configure the global DPIFactor variable from the application.startup event.

And last but not least:

DO NOT open the application in Visual Studio from a resolution other than the original one, or ALL YOUR CONTROLS will move and resize when each form is opened, and there is no turning back ...

Hope this helps, happy programming.

-one
Dec 30 '10 at 16:33
source share



All Articles