|
-
Nov 24th, 2015, 01:33 AM
#1
Thread Starter
Fanatic Member
Form and Grid Display in high DPI
Hello Everyone,
I have an application that I made over the years. The development environment is VS 2008 and it uses .net framework 3.5.
There are two problems basically:
1) Form display gets affected if DPI changes to a value greater than 100%
2) Grid cells also show clipped text / column sizes reduces
To correct the first one I had to use table layout control in forms and set form properties like AutoSize = True and AutoScaleMode to Font etc.
In case of second issue i.e. data grid columns and text what should I do. When I developed I didn't take font/DPI into account. So all the columns have fixed sizes based on what I thought was okay if DPI is normal i.e. 100%.
How do I fix the above?
Thanks,
Cheers,
GR
-
Nov 24th, 2015, 01:26 PM
#2
Re: Form and Grid Display in high DPI
Well, you can always switch to using percentages or autosizing for the columns, but that's not always adequate as well.
I recently talked to another person about high DPI in WinForms, and it's a really difficult topic. All of the WinForms technologies are pretty old, the last big improvement was acknowledging that people might want to alpha-blend around the Windows 2000 era. This is sort of why MS said "Hi, could everyone please use WPF? We don't want to lose a lot of money to Apple..." but no one listened because lol learning new things.
You can, with effort, measure how big your strings will be on the current display and adjust sizes that way. Or, you can determine the current DPI and do your own scaling: the Windows Forms scaling is kind of bad. It could be that with your layout on that screen, you can't reasonably fit everything. That'd suggest having two copies of the form, which isn't as bad as it sounds if you're separating UI code from normal code.
This answer is wrong. You should be using TableAdapter and Dictionaries instead.
-
Nov 26th, 2015, 08:46 AM
#3
Thread Starter
Fanatic Member
Re: Form and Grid Display in high DPI
 Originally Posted by Sitten Spynne
Well, you can always switch to using percentages or autosizing for the columns, but that's not always adequate as well.
I recently talked to another person about high DPI in WinForms, and it's a really difficult topic. All of the WinForms technologies are pretty old, the last big improvement was acknowledging that people might want to alpha-blend around the Windows 2000 era. This is sort of why MS said "Hi, could everyone please use WPF? We don't want to lose a lot of money to Apple..." but no one listened because lol learning new things.
You can, with effort, measure how big your strings will be on the current display and adjust sizes that way. Or, you can determine the current DPI and do your own scaling: the Windows Forms scaling is kind of bad. It could be that with your layout on that screen, you can't reasonably fit everything. That'd suggest having two copies of the form, which isn't as bad as it sounds if you're separating UI code from normal code.
Thanks for your reply. What would be easiest way to display text in grids without writing too much code. The thing is grid is used extensively in my application and it will take me long to fix it. In most cases the column sizes have to be appropriate. Then even if the text is long it can get truncated. I cannot fiddle with autosize otherwise it will increase col size way beyond whats needed.
In device for e.g Surface Pro the resolution is high and change the size of text etc is 200% by default. Here if I try to determine DPI it gives me 96 which is normal I think. So what do I do.
-
Nov 26th, 2015, 08:01 PM
#4
Re: Form and Grid Display in high DPI
 Originally Posted by greatchap
In device for e.g Surface Pro the resolution is high and change the size of text etc is 200% by default. Here if I try to determine DPI it gives me 96 which is normal I think. So what do I do.
This is because your application is not configured to proclaim that it is DPI-aware. Many of the problems that you are experiencing are due to what is termed DPI virtualization. the The Desktop Windows Manager (DWM) performs a bitmap scaling of the rendered window on non DPI-aware applications to try to make them workable in the modern environment. Problems occur because the virtualization environment tells your application that it drawing to a 96 DPI window. Winforms has two mechanisms to accommodate scaling (DPI and Font), but if it is told the improper DPI setting, that is all it has to work with and will not perform properly (garbage in - garbage out syndrome). I recommend that you disable all WinForms automatic scaling and handle it in code by setting the Form.AutoScaleMode to None.
The first step is to read: Writing DPI-Aware Desktop and Win32 Applications An older but more direct tutorial is: How to Write High-DPI Applications. Both these tutorials are written for a C programmer audience, so the relevant parts need to be stated in .Net terminology. The first one is very educational in that in describes the fast pace at which changes in the way Windows deals with DPI settings has advanced with each new Windows version. A third article that explains some of the tribulations of dealing with DPI is: High DPI Settings in Windows. This last article offers ways of dealing with the issue after the fact, but the best solution is to code you application to be DPI-aware.
Making your application DPI-aware is is done by modifying the app.manifest. You access the manifest through the project properties (Project Menu->Project Properties-Application Tab->View UAC Settings Button(this is the button name in VS2008. Later verions name this button "View Window Settings"). You should see something like this:
Code:
<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
</asmv1:assembly>
What you want to do is add this declaration to that file under the root tag (<asmv1:assembly>.
Code:
<asmv1:application>
<asmv1:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv1:windowsSettings>
</asmv1:application>
I have embolden "asmv1" because the example in the first tutorial uses "asmv3:application" and people oftern just cut and paste that from the tutorial; the "asmvX" part must be consistent with that of your application.
The next part is to determine the scaling factor. I recommend that you declare a variable in your code to store the DPI setting that was in force during development as opposed to assuming that it was 96 DPI.
Code:
Private designDPI As PointF = New PointF(96.0F, 96.0F)
The second tutorial shows using GetDeviceCaps with the LOGPIXELSX and LOGPIXELSY arguments to determine the DPI. You can accomplish obtain the DPI value from the System.Drawing.Graphics object obtained by calling the Control.CreateGraphics or as shown below.
Code:
Private Shared Function GetDPIForScreenHostingForm(frm As System.Windows.Forms.Form) As PointF
Dim ret As PointF
Using g As Graphics = Graphics.FromHwnd(frm.Handle)
ret.X = g.DpiX
ret.Y = g.DpiY
End Using
Return ret
End Function
Now you can calculate the DPI scale factor.
Code:
Private Shared Function DPIScaleFactor(frm As System.Windows.Forms.Form, designDPI As System.Drawing.PointF) As SizeF
Dim currentDPI As PointF = GetDPIForScreenHostingForm(frm)
Dim xFactor As Single = currentDPI.X / designDPI.X
Dim yFactor As Single = currentDPI.Y / designDPI.Y
Return New SizeF(xFactor, yFactor)
End Function
You apply the scale factor to the Form and its child controls by calling the Form's Scale method.
Code:
Me.Scale(DPIScaleFactor(Me, designDPI))
This code should be executed after your Form loads in the Form.Load handler. It should also be executed with modification, if the DPI changes while your program is executing. I will leave it to you to make the modification to the scaling factor to account for a previously applied scaling factor.
To detect changes to the DPI while the application is running, you need to subscribe to the
Code:
Microsoft.Win32.SystemEvents.DisplaySettingsChanged
event and handle that appropriately.
The above only addresses DPI scaling. You may also want to address display resolution to maintain relative shape as well. For this you can use the System.Windows.Forms.Screen class to obtain those metrics.
Again read the tutorials, I have listed. There are many other programming issues that I have not covered above that may apply to your program. Always test your program at different DPI settings to ensure that all is scaling properly. Some controls may not automatically scale with the Form or incompletely scale and will need to be addressed individually.
-
Nov 27th, 2015, 12:58 AM
#5
Thread Starter
Fanatic Member
Re: Form and Grid Display in high DPI
Thanks a lot for the info TnTinMN. I will surely go through it.
While changing the application to suit High DPI will be a lengthy process, I figured out that changing form autoscale factor to Font and using Table layout control does solve most of the layout problems. Maybe this is a quick fix but it will do the job for now. The problem that is currently persisting is text shown in data grids. The columns get truncated. The column sizes were hardcoded based on default DPI. So in order to fix that do I need to determine width of datagrid and tweak column width based on % or is there another way.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|