When per-monitor DPI changes (WM_DPICHANGED message), the built-in scrollbars of controls like list view, tree view, rich edit, listbox are not scaled (as expected).
They need to be scaled programmatically.
Though I didn't find any API (neither in Win32, let alone in WinForms) to set scrollbar size.
What API can I use to set scrollbar size (width)?
Or at least how I do get hold of the scrollbar handle? (I assume that internally the scrollbars are separate child controls) Once I have the handle, I assume I can use MoveWindow to resize it (Edit: my assumption was incorrect, as the answer by #Anders shows)
For a background, see High DPI Desktop Application Development on Windows.
There are couple seemingly duplicate questions, but none of them are actually relevant:
Winforms - Adjust width of vertical scrollbar on CheckedListBox
Change width of scrollbars
The answers there either change system-wide settings or work for DataGrid only (that have separate child scrollbar controls available in its interface).
Scrollbars are usually not separate windows. If a window uses the WS_HSCROLL/WS_VSCROLL styles then the scrollbars are implemented in the non-client area of the control itself.
Windows 10 Creators Update is going to introduce something called Per Monitor V2 DPI awareness. This includes child window notifications, "Windows Forms DPI scaling improvements" and "Improved theming behavior". It is also going to automatically scale the non-client area.
In the meantime you can try calling EnableNonClientDpiScaling in WM_NCCREATE (added in the Anniversary Update).
As suggested by #Anders, the Per Monitor V2 DPI awareness in Windows 10 Creators Update resolves this.
To enable Per Monitor V2 DPI awareness, while still supporting old Per Monitor DPI awareness on older Windows 10 builds and Windows 8.1 and DPI awareness on yet older versions of Windows, make your application manifest like this:
<assembly ...>
<!-- ... --->
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>True/PM</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2,PerMonitor</dpiAwareness>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>
References:
High DPI Improvements for Desktop App Developers in the Windows 10 Creators Update – video (archived)
Application Manifests – reference
Related
Simillar question has been asked but I don't think accent was on this.
When I change DPI in Display settings my application becomes blury. If I change DPI settings, than log out and log back in, everything is fine.
My question is - why is OS making my application blury when changing DPI but OS apps like Explorer, Settings, Paint and rest are not blury?
Mentioned OS apps are being resized accordingly to DPI and it is obvious their fonts are crystal clear and crisp. Why is this not happening to my application.
I added dpiAware option in manifest but that doesn't seem to change anything.
Just to note again - I am talking about changing DPI in real time and observing how my application acts and how OS apps act.
You might want to look into SnapsToDevicePixels Property of UIElement
I recently introduced a WPF control to my VB.net WinForms application. The control looks good and works great. However, depending on which environment I run the application, I will get different behavior. The two machines that differ are both running Windows 8.1 with the default theme.
I have read a few questions about adding proper theme settings and I don't believe that is the issue.
In the environment that is incorrect I have observed the following behavior:
Upon loading the form containing the WPF control, the calling form will resize and move around the screen
Controls contained within the form that also contains the WPF control will often "ghost" upon resizing the application
Both the calling form and the form containing the WPF control shrank upon loading the containing form. By shrank I mean window size, control size of all controls, font size, etc...
I'm wondering if the application was built against one version of the library and the DLL versions differ on the deployment environments. But I'm not sure how to look for this.
Has anyone encountered this before?
I found the problem.
This was the result of DPI scaling. The application was acting out anytime the DPI settings were set to anything other than 100%. WPF controls scale differently from Winform controls causing the strange behavior. The following stackoverflow Q/A explains how to remove the DPI dependency
Disable DPI awareness for WPF application
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.
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.
I know that this can be controlled at the system level, but I want to override the system setting and have a certain appearance for only my application. I'm assuming there must be a Windows API function to control this because I've seen another windows app that does it.
(It is not necessary to go into the reasons why I should not do this)
If you want a custom appearance for your application, I would just make my form borderless and handle everything myself, either by drawing on the form itself in the Paint event, or else moving controls around (panels etc.) in the Resize event. You have to handle things like dragging, resizing, closing/minimizing etc., but none of this is especially difficult.
Here is my answer to a similar question, which shows the basics of doing it yourself (it's for windows mobile, but it will work in regular windows too).
These outer elements of an applications window are collectively referred to as the windows "chrome" and are indeed rendered by the operating system. Various flags are used at the windows API level to controls certain aspects of each window instance (e.g. the existing of a control box, border, min/max buttons, etc.), but the border width for resizable windows is determined by a system setting to ensure uniformity and is not configurable on a window by window basis.
You can, in many instances, gain control over some of the aspects of your window not exposed by .NET by interacting with the windows API and it is beneficial to read the windows API documentation to determine just what is possible at that lower level. I suggest reading the documentation for CreateWindowEx as a starting point.
http://msdn.microsoft.com/en-us/library/ms632680(VS.85).aspx
.NET allows you to change the FormBorderStyle property to select among no border, single pixel width border, and resizable (thick border). If you'd like to do something custom, you'll have to set the .NET border style to none, and then assume the responsibility for rendering the window chrome yourself. This entails rendering your own caption bar, min/max buttons, and window border. It's not a light undertaking, but many apps do it. It's a long way to go if all you really want is to control the border width.
This article goes into how one might approach this task in WPF, and may also be of use.
Window Chrome In WPF