question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Define a pattern for default values that used to be constants proportional to the default system font.

See original GitHub issue

related bugs

The background

Some control properties are decorated with a DefaultValueAttribute. When control is created in the designer, and the property had not been initialized yet, property browser reads attribute value and shows it in the property browser. If the user changes such a value in the property browser, design time serialization writes the user-specified value into the InitializeComponent method in the code-behind file. If the user does not assign specific value to such a property in the property browser, this property will not be serialized into the code-behind file, as controlled on line 1176 by the type description provider. Default value is also used to reset property value in the property browser.

At the runtime, properties that are not assigned to in the InitializeComponent method, are initialized to default runtime values.

Design time components assume that the runtime default value is the same as the design time one i.e., in the case when the attribute is used, the same as the attribute value. If this assumption is not upheld, the reset option in the property browser will not work, and InitializeComponent will explicitly serialize default values instead of letting the control to pick up the runtime default on the initialization.

The issue

In some cases, the default runtime value is dependent on the application font. For example, Height or Width properties. Some of these values had been calculated and hardcoded before we have changed the default font. Currently some of the design time default values defined in the attribute are out of sync with the runtime default values that are explicitly assigned in the constructor.

Example

Design time default value - https://github.com/dotnet/winforms/blob/62edc1ab7b601bee58199fdea2580a54cf5cd25b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewRow.cs#L212-L218

Runtime default - https://github.com/dotnet/winforms/blob/62edc1ab7b601bee58199fdea2580a54cf5cd25b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewRow.cs#L37

The runtime value is dynamically calculated based on the default font while the designer assumes a constant value.

What happens

  1. when designer is shown, control is instantiated, and the runtime default value is assigned to the property.
  2. when control is serialized, TypeDescriptor compares the actual property value (from the runtime default) against the value in the attribute, sees that they are different and adds a line that sets this value to the InitalizeComponent. Problem: User had not edited this value and expects that height is picked up from the font, user changes the control font on the startup and the height is not appropriate for the new font.

Suggestion

Use a different pattern to supply the default value, like what ambient properties are already using. See line 1170.

  1. remove the default value attribute from properties that have dynamic default values.
  2. add Reset<Property> and ShouldSerialize<Property> methods that compare actual value against the dynamic runtime default.

This is a breaking change

Per https://github.com/dotnet/runtime/blob/main/docs/coding-guidelines/breaking-change-rules.md#attributes. But I consider this case a grey area because the functionality is preserved, and change is unobservable to the user unless they enumerate the attributes. If they enumerate the attributes, they’ll have to look up the breaking changes docs. If default value functionality is consumed through the TypeDescriptor infrastructure, for serialization purposes, there will be no change.

A pseudocode representation of the pattern.

before:

namespace System.Windows.Forms;

public class SomeControl : Control
{
    private const int DefaultHeight = 22;

    public SomeControl()
    {
        Height = DefaultHeight;
    }

    [DefaultValue(DefaultHeight)] 
    public int Height {set; get;}
}

after:

namespace System.Windows.Forms;

public class SomeControl : Control
{
    public SomeControl()
    {
        Height = DefaultHeight;
    }

    private int DefaultFont { get; }

    public int Height 
    {
          // Calculate the height to accommodate text that uses the default font, i.e. use Control.DefaultFont.Height   
         set; get;
    }

    private void ResetHeight()
    {
        Height = DefaultHeight;
    }

    private bool ShouldSerializeHeight()
    {
        return Height != DefaultHeight;
    }
}

Issue Analytics

  • State:closed
  • Created 7 months ago
  • Reactions:1
  • Comments:9 (9 by maintainers)

github_iconTop GitHub Comments

2reactions
Tanya-Solyanikcommented, Feb 15, 2023

@kirsan31 - sure, I will investigate this bug after the attribute removal is approved. So far, the root cause seems to be that the font is not recognized as the default one.

1reaction
terrajobstcommented, Feb 23, 2023

Video

Looks good as proposed.

We discussed whether the methods ResetXxx() and ShouldSerializeXxx() should be public. We concluded that they shouldn’t be because they are indirectly used by TypeDescriptor, which is the way the designer (and other serializers) should interact with these types.

It looks like we might want to consider an analyzer that checks for an assignment of ItemHeight and instructs the user to delete the line. Alternatively, the designer could me made aware of which properties are DPI dependent and doesn’t persist those values to hardcoded values into the designer generated code. It sounds like this is planned for a later day.

Read more comments on GitHub >

github_iconTop Results From Across the Web

SystemFonts.DefaultFont Property (System.Drawing)
The following table describes the value returned by the DefaultFont property depending on the operating system and local culture. System and/or culture, Font...
Read more >
Ubuntu Manpage: fonts.conf - Font configuration files
Fontconfig is a library designed to provide system-wide font configuration, ... After the pattern has been edited, a sequence of default substitutions are ......
Read more >
5 Font Specification - X Window System User's Guide ...
The “fixed” alias is used as the default font for xterm windows. ... A value describing a font's proportionate width, according to the...
Read more >
CSS Fonts Module Level 3
Abstract. This CSS3 module describes how font properties are specified and how font resources are loaded dynamically. The contents of this ...
Read more >
TextItem (tx) Resources
If this resource has the value 0.0, TextItem draws characters with proportional spacing; in other words, each character is spaced according to its...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found