Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Improved dpi scaling and support for logical coordinates #305
This issue is created as requested for PR #279 to discuss the proposed improvements and new APIs.
Current status of dpi scaling
Here is some of the insight I have gained into the current dpi scaling implementation by going throught the current codebase. Please correct me if I got something wrong:
Issues with the current implementation
The biggest flaw is that the code (and the APIs) are based on physical pixels instead of logical coordinates/effective pixels. Thus, each control and application needs to do the coordinate transformation itself, which is challenging and prone to errors. Unfortunately, there is not really a low-level visual positioning and rendering layer where this transformation could be done. Instead, a lot of code directly calls into the win32 (pixel based) functions. Therefore, improvements of the current implementation seems to be the most reasonable approach. The next big issues I have encountered is that there is currently no way to know to which dpi a control is actually scaled to. There is the DeviceDpi property, but this one is for example completely unrelated to the scaling initiated by the AutoScaleMode pass. Setting one of the properties of a control (e.g. the width) can have a completely different result depending on where it is done in the code.
Some additional issues:
Improvements of the general scaling mechanism
The PR adds a new code path that can be enabled for a single control with the LogicalDpiScaling property or by default with the Application.SetLogicalDpiScalingDefault() method. The basic idea is that each control keeps track on the dpi value it is currently scaled to and rescales itself if necessary (and ignores AutoScale changes):
These changes should especially improve the initial positioning of the controls and sizes of the fonts. Additionally, per monitor v1 support is now basically on-par with the v2 version (except for its fundamental limitations). Because the dpi value for each control is always known, new APIs can be added that transform between logical and pixel coordinates in a reliable way.
New APIs for logical coordinates
The new APIs in the Control class are supposed to be used in applications and new controls. The final goal is that they can always stay in the logical coordinate space and do not have to worry about dpi scaling. The positioning APIs should also be usable with existing controls.
Bitmaps (not in the PR)
Unlike vector graphics and font rendering, bitmaps are inherently pixel based. It would be great if there would be APIs for the application to provide bitmaps in different sizes and the best fit for the current dpi would automatically be picked.
I hope the proposed changes provide valuable improvements of the current dpi scaling mechanism that can be easily integrated into existing applications. In addition, they are compatible with the already present dpi support code in the various controls. The added APIs can be leveraged to write new code in a dpi independent way.
This is a large feature request and not fully in scope for the 3.0 release. However we are actively investigating ways we can improve Per Monitor support for all of our controls. I added the API suggestion tag because we will need to also discuss options around adding to the API and whether that's a good option or not. Thanks @lhak for kicking off the discussions.
@lhak Given what @merriemcgaw said regarding how this change is not likely to be merged any time soon, I have a question for you. Is there any way I can glue your changes on top of an otherwise-unmodified copy of winforms (via subclassing, extension methods, etc.)?
I have had to jury-rig a custom
@wjk you should work with @KlausLoeffelmann , he's been working on the ToolStrip and I'm pretty sure he ported some fixes into .NET Core rather recently (or it's in the works :)).
Yes, the Toolstrip is in the works - actually, it is ready, but for easier testing, we should have the HighDpiMode API extension in, before we PR the toolstrip.
Also, without having taken a look at the correlating PR yet - if we really want to approach a big change like the proposed, let's think about having appropriate analyzers to guarantee consistency in the changes. Tests alone would not be enough for me to let me sleep OK at night.
@wjk The toolstrip controls (without the upcoming changes) all seem to be system dpi aware, so they should scale in (many) static scenarios. However, I have seen in the code that some values are not scaled (e.g. the number of dots in the grip will change, but not their sizes). Are these the kind of differences you have mentioned? The changes in the PR will not magically fix this, but they should make it easier to write code that achieves what you are asking for (i.e. the rendering at different dpi values basically looks the same, just sharper).
@lhak Please see the attached project. At 100% scaling/96 DPI, the custom ToolStripRenderer draws exactly as I desire it to. If you run this code at any higher scaling value, while most of the custom drawing is correct, things like rounded corners and arrow glyphs are incorrectly scaled. My goal with this code is to have the custom drawing look identical at 100% scaling and higher, even if the code used to generate it is different.
In another version of this code (not attached, sorry) I attempted to use the