Windows 10 display scaling - winforms

I have an application which uses three UI frameworks:
OWL
Windows Forms
WPF
The WinForms and WPF forms and dialogs use fonts that are noticeably smaller than the OWL fonts.
If I use DPI scaling (to 125%) in Windows 10, it does a very good job of upscaling a Windows Forms dialog. If I use Scale on a Windows Form it only scales the controls and not the fonts. If I use the functions suggested here:
https://github.com/Microsoft/WPF-Samples/blob/master/PerMonitorDPI/WinFormsHost/MainWindow.xaml.cs
I get scaled controls but not fonts if I only use the form scaling. If I use the extra font scaling functions, that increases the size of the dialog way beyond the original desired scaling (from 1.25 to 1.6 roughly).
Does anyone know how to scale a WinForms form properly like Windows 10 seems to be able to (without changing screen DPI setting to 125%)?

The answer is to place everything in a flow layout or a table layout. Then spend time figuring out how to make sure they layout correctly.
A better answer would be WPF but that's not always an answer.

Related

Difference in display of WPF and Windows Forms applications

Actually, I have started learning WPF. I have few months of experience in developing Windows Forms applications. Though, I am getting the meaning of a WPF application, but still I am not able to differentiate the difference between two, on the basis of their output.
With reference to this Link: Device Independent Pixel (DPI), I have learnt that whenever the operating system render a WPF application it manages its size itself according to its resolution.
So to check this difference, I created two demo applications in both frameworks and changed the resolutions as well.. but I didn't find any satisfactory difference. Which could explain it is a WPF application and this one is a Windows Forms application.
It does not create any scroll bar on maximizing and doesn't make the button big or small on changing the resolution.
I have read somewhere that Visual Studio 2010 has been rewritten in WPF. But in my experimentation I saw that, (on changing the resolution of desktop) it makes text and graphics unreadable/blurry. On re-sizing its window, everything was getting hidden except the menu-bar. And the menu-bar content was shifting its positioning, e.g. far right one menu items were shifting down. Why?
Kindly make me correct & explain a little more bit (this display issue) too.
To answer this question properly I should write a whole chapter, but I keep it short:
There are three major differences between a WPF application and a Windows Forms application: Layout, Render, Presentation
Layout:
WPF layout system provides a greater flexibility in arranging the elements on the fly. It is based on the Element Bounding Box (as opposed to precise pixels in WinForms) and Measure and Arrange mechanics (as opposed to UpdateLayout in WinForms) that automatically and dynamically finds the place for each element without any need for a manual update.
Basically, all elements bounding box are measured first and then are arranged using multiple methods such as Measure, MeasureCore, ArrangeCore, MeasureOverride, etc.
Unlike WinForms, where you have a pixel-perfect size for everything, in WPF you have much more options and complexity such as Width, ActualWidth and DesiredSize (and even Transforms as LayoutTransform) for the same element.
This is why
As you type in a WPF TextBox, its width might increase and push other elements away or even push some elements into a new row (like the menu bar you've observed)
As the size of a control changes, it affects the available space for other elements. So their size and location might change accordingly.
When the window is being re-sized or resolution is changed, it immediately updates the layout and changes the size of elements in order to fill or fit the space. Here you'll find out more about Layouts.
using Margin alone (without using layout capabilities) to arrange elements is not the best idea in WPF. As it's the WinForms mindset which isn't much helpful while developing WPF.
Render:
WPF uses double data type for Layout (as opposed to pixel-perfect WinForms) and therefore you might see the edges blurry sometimes, but it can be avoided with SnapToDevicePixels=true.
WPF is much more efficient in utilizing the GPU to render a GUI. Try a grid of 30x30 TextBoxes in a Windows Forms application and a WPF application. No matter how messy you write the WPF, it never blinks and it still runs much faster than Windows Forms. Even adding a handful of animations, visual effects and styles on them does not hurt your performance like in Windows Forms.
Remark: To avoid a speed decrease and blinking in a Windows Forms application, you should set DoubleBuffer of the form to "true".
You can use any Transform as RenderTransform to easily implement smooth zoom/rotate, or develop custom GPU-based shader effects, and much more in WPF. (I think everyone agrees that doing such things in WinForms is feasible but real pain and you most likely will give up and move to GDI+ or DX if not out of frustration then because of the bad performance.)
And the last and the most important:
Focus on presentation:
When develping WPF Applications you have to stop thinking in Windows Forms: No more UI events, accessing controls by their names and writing logic in code-behind and start to think in WPF: Binding, Commands, Resources, Styles, Templates, Converters, DependencyProperties and their callbacks.
The real power of WPF lies in separation of 'View' and 'Logic', Which can be achieved using the MVVM pattern.
It makes the most visually-complicated problems quite simple and easy to develop and easy to write Unit Tests for.
Once you got the hang of it, you will realize there's no limit in how you can present the data or show off an awesome GUI looks.
If you've planned to switch to WPF, you've made the right decision. Always stick to MVVM and AVOID CODE-BEHIND AT ALL COSTS! (i.e. unless you are doing a pure UI operation: do not write code in .xaml.cs files, do not access x:Name in cs files and avoid UI events.)
Windows Forms (WinForms) and Windows Presentation Foundation (WPF) are two different ways of building the user interface for your application. Windows Forms is the older technology and its controls are found in the System.Windows.Forms namespace. WPF is a newer technology and its controls are found in the System.Windows.Controls namespace.
WPF
Pros:
Powerful styling and skinning structure
Easy to create your own look and feel
Does support Windows Forms
The future technology for developing Windows Vista applications
The ability to reuse existing code
Highly advanced data binding possible
Cons:
Declarative vs. procedural code
Requires .NET Framework 3.0
Compared to Windows Forms, still in development phase
Requires Dx9 compatible video card for advanced graphics
Windows Forms
Pros:
Extensive documentation to be found on the Internet
Plenty of examples
Does support WPF
Cons:
How long will this be supported? (I've read somewhere that Microsoft is just developing WPF now, only maintenance for Windows Forms).
Design your own look and feel in an application is a lot of work.

When using the WinForms designer, do I always need to have DPI set to 96?

With my current monitor I prefer a DPI setting of 120 pixels per inch (which windows suggests as the default). However, after designing a form, it often lays out incorrectly on systems that don't use 120 pixels per inch.
I'm wondering, is it necessary that I should set my display settings to 96 pixels per inch for whenever I use the designer?
Also, there are some problems when other developers have different DPIs. They open a form in the designer and move something like a text edit control, and suddenly find that it automatically resizes itself too. Then, there's one control that's a different size to the others and we're in a mess.
P.S. I've read related posts. They're all interesting, but didn't answer my question.
How to control the font DPI in .NET WinForms app
C# WinForms disable DPI scaling
WinForms Different DPI Layouts
DPI not scaling properly
Visual Studio and DPI issue
No. You don't need to always have the DPI set to 96 when using the WinForms designer.
If you set the AutoScaleMode property to Dpi then the designer will write the current system DPI into the designer.cs file in the AutoScaleDimensions property for the form. When the designer is used on a system with a different DPI, this information will be used to rescale the form and the designer can be used at a different DPI.
When I tried other scaling modes, this didn't seem to work well. 'None' meant that controls wouldn't scale at runtime, 'Font' seemed to suffer from rounding errors and when the display settings DPI changed, the control sizes could change slightly causing errors.
I also found that for UserControls that are added to forms it is best to set their AutoScaleMode to Inherit. If you use Dpi, then the controls on it get re-scaled twice and will end up being laid out incorrectly.
I came up with the guidelines above after a few hours of experimentation and internet searching where I found the following two articles:
Automatic scaling in Windows Forms
and:
Child controls on a UserControl may get clipped in a system with a lower Font Dpi
I don't think setting your dpi to a different value permanently will help you. The problem is that there are problems when you change the dpi, i.e. the form layout you have isn't able to deal with different dpi's.
I don't have an absolute solution for you, except that you should test with different dpis and see if it produces problems with the form display. It isn't hard to work out what causes problems and you'll learn what to avoid fairly quickly.

WPF high dpi issues

I created a simple web browser WPF test application with pictures and text within a canvas, with windows set at 96dpi.
Then I switched to 120 dpi and :-((( Display is messy, image size changed and part of the canvas is out of view...
When I used Winforms, I set the AutoScaleMode property to None and the windows keeps its size, the controls as well, the controls which have inherited font are properly displayed, not blurry and not too big...
What can I do to mimic this (good) behavior in W¨F?
I'm not clear on what you mean by "web browser WPF ... application". WPF doesn't run in a Web browser, unless you're talking about an XBAP. Or are you doing Silverlight? Or is it just a WPF navigation application and not browser-based at all? You'll need to clarify.
WPF automatically scales your content when you run in high-DPI modes. This is intended behavior: if the user explicitly says they want everything to be bigger on the screen, then WPF will respect the user's wishes. The old WinForms hacks of "pretend high-DPI doesn't exist, just show everything at the normal small size and hope it doesn't piss the user off too much" aren't available in WPF; you could probably emulate them if you worked at it, but you're steered very strongly toward doing the Right Thing.
WPF scales everything, so your statement that "part of the canvas is out of view" doesn't make sense. It should be scaling the canvas, its parent window, and its child elements all by the same amount, so if everything fits at 96dpi, it should also fit at 120dpi and 144dpi. If not, then you're doing something strange and you'll have to provide a code sample that reproduces the problem.
You seem to be claiming that fonts are blurry when you run in a high-DPI mode, which sounds very strange. Fonts are rendered as vectors, so they should scale cleanly, and render crisply even in high-DPI modes. I've never seen the blurry fonts you describe, so again, you'll have to provide a repro case.
The only thing that I would expect to be blurry are images. If you're using raster (bitmap) images (BMP / GIF / JPG / PNG) in your UI -- for example, for the icons on a toolbar -- then yes, those will look pretty bad when they're scaled. It pretty much always looks bad when you take a small bitmap and make it larger. You might try working around this by using larger images and sizing them down for display -- for example, if you want your toolbar images to be 16x16 (when in standard 96-dpi mode), then you could try putting a 32x32 bitmap in your project, setting the Image element's Width="16" and Height="16" in your XAML, and seeing if that looks any better. It would actually be 20x20 physical pixels in 120dpi mode, and 24x24 in 144dpi mode, both of which would still be scaled down from the 32x32 resource and would therefore have a better shot of looking good than a 16x16 source image that's had to be scaled up. (I haven't tried this technique in a WPF toolbar, though, so I don't know how well it would really work in practice with typical toolbar images.)
The very best way to get around the problems with scaling images would be to use vector images instead of raster. Unfortunately, it's hard to find libraries of vector images. They're few, far between, typically less comprehensive than what you can find for bitmap images, and often expensive.
Presumably you use fixed length units (px). Try re-layouting your project keeping the WPF layout rules in mind. This page has some best practices for that.
I just found a bug using MaxHeight under WPF in .NET 4, set in a Style that gets inherited by another Style and that is used as a StaticResource, which didn't get influenced by the DPI set by the user. I set it from MaxHeight to Height, then it got influenced by the DPI. I suspect a bug in the .NET 4 (and possibly other frameworks) here.

Why do I see pixels when zooming WPF application in Windows?

I have developed a GUI for a random application using WPF. I have a bunch of out of box WPF controls laid on the application window. I haven't customized anything, didn't use bitmaps, etc.
When running my application and zooming using Magnifier application in Windows 7 (Win key + Plus key, the magnified GUI is showing pixels.I am probably wrong, because I can't explain it otherwise, but isn't WPF supposed to provide vector like control rendering?
Thanks for participating in the discussion.
Bonus Reading
Tim Sneath: Magnifier: An Interesting Discovery (archive)
WPF Vector based interface *(screenshot of WPF being vector scaled by Magnifier)
MSDN Blogs: Greg Schechter explains why it longer happens (archive)
Back when Vista first shipped, and when WPF was on version 3.0, zooming with the built-in magnifier would actually do vector-based scaling.
This stopped working when WPF 3.5 service pack 1 shipped. (It worked in 3.5 before sp1.) The reason it worked before then is that the DWM (Desktop Window Manager) - the part of Windows responsible for presenting everything you see on screen - uses MILCORE.DLL to do its rendering. Version 3.0 and 3.5 of WPF also used this same component to render - this meant that all WPF content was native content, so to speak. (In fact, on Windows XP, which doesn't have the DWM, MILCORE.DLL is something that WPF puts on your system for its own benefit. But it's built into Vista and Windows 7.) When WPF was using MILCORE.DLL to render on Vista, any effects applied by the DWM such as scaling would also apply in the way you want to WPF - it really did scale without pixelating.
Unfortunately, this is no longer the case. And the reason is that WPF started adding new rendering features. In 3.5 sp1, the new feature in question was support for custom pixel shaders. To enable that, Microsoft had to release an update to the MIL. (The Media Integration Layer - the bit that does the actual rendering.) However, they weren't really in a position to update MILCORE.DLL, because that's part of Windows - it's how everything you see on screen gets to be on screen. Releasing a new version of MILCORE.DLL effectively means pushing out an update to Windows. The release schedule for Windows is independent of that for .NET, and so the only way the WPF team could reasonably add new features was to ship a new MIL. (In theory they could have done it via Windows Update, but since WPF is now owned by a different division of Microsoft than Windows, that sort of thing doesn't seem to happen in practice.)
As of .NET 3.5 sp1, the MIL is in a different DLL called wpf_gfx_vXXXX.dll where vXXXX is the version number. In .NET 4.0, it's wpf_gfx_v0400.dll.
The upside is that WPF gets to add new rendering features with each new version, without needing Windows itself to be updated. The downside is that WPF's rendering is no longer as tightly integrated with Windows as it was briefly back when Vista shipped. And the upshot is, as you've seen, that magnifying is not as much fun as it used to be.
The magnifier application implements its own zoomed image rendering, so that's why you are seeing pixels. WPF does use vector graphics, but in this situation it's not the WPF application itself that is rendering the zoomed image.
If you use something like Snoop you can see zoomed and scaled WPF vector graphics rendering in action.
I suppose, Windows 7 magnifier takes a snapshot of actual application on-screen UI, and then magnifies it itself (not making a special case for WPF applications). Of course what it can access is just the pixels, not the vector graphics which works behind the scene.
The Windows-7-Magnifier is pixel based, but there is a difference in magnifier mode depending on wether an Aero-theme is active or not.
with Areo theme the zoom is pixelated.
without Areo theme the zoom is smoothed (blurry).
Only with Areo theme other Views (except "Docked") are selectable.

Is there a WPF equaivalent to System.Windows.Forms.Screen?

I'm trying to create a WPF window that will encompass the entire Desktop working area. In WinForms I'd do this by getting the Union of all the bounds in System.Windows.Forms.Screen.AllScreens.
Is there an equivalent type or other mechanism to get the bounds of the entire desktop in WPF or do I need to use the WinForms type?
Try SystemParameters.VirtualScreen* (Top, Left, Height, and Width) properties. http://msdn.microsoft.com/en-us/library/system.windows.systemparameters.virtualscreenheight(v=VS.100).aspx
Don't use winforms api because it doesn't take into account the fact that WPF's measurement units are not pixels. I came across this issue just recently because I'm losing my vision and have my monitor set to a higher dpi. The codebase I was working on used the Winforms Settings and the UI was larger than my screen.
If you're going to use the winforms api. Look at this blog post on calculating the DPI factor.
I have successfully used WpfScreenHelper 0.3.0.0, currently on Github or Nuget,
https://github.com/micdenny/WpfScreenHelper
It does what the .NET framework should have done so many years ago.
I needed to check if some coordinates exist on any screen in WPF, as in these:
Very germane: Determine if an open WPF window is visible on any monitor
Forms-only and inadequate WPF suggestions: Determining if a form is completely off screen
Just use WinForms. I do not think there is a direct WPF equivalent.
You could try SystemParameters.VirtualScreenWidth and associated parameters. That might not provide as good as a result as continuing with the WinForms API.
The only downside I can see with the WinForms type is an extra dependency and the larger working set related to that.

Resources