4

I have a class library with a custom control in it:

using System.ComponentModel;
using System.Windows.Forms;

namespace ClassLibrary1
{
    public sealed class CustomLabel : Label
    {
        [DefaultValue(false), Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override bool AutoSize
        {
            get => base.AutoSize;
            set => base.AutoSize = value;
        }

        public CustomLabel()
        {
            AutoSize = false;
        }
    }
}

Notice that AutoSize is set to false in both the constructor and the designer attribute on the overridden method.

I have a winforms project where I want to use the control. I drag/drop it from the toolbox, but it doesn't have AutoSize set to false:

enter image description here

If I save and close the form and then re-open it, now it's set correctly:

enter image description here

How can I make it respect the property value when first dropped on the form?

rory.ap
  • 34,009
  • 10
  • 83
  • 174
  • Could it be something connected to the DesignMode property? I would look to see if something changes when you test that property. https://stackoverflow.com/questions/336817/how-can-i-detect-whether-a-user-control-is-running-in-the-ide-in-debug-mode-or – Steve Jan 19 '18 at 17:49
  • It's not connected to `DesignMode` property, but related to designer. It's because of `CreateComponentsCore` method of `AutoSizeToolboxItem` which is set as `ToolboxItem` of the Label. – Reza Aghaei Jan 20 '18 at 08:13
  • I should also add, the `CreateComponentCore` method will just run when you drop the component from toolbox to design surface. It describes why after dropping it on form, it's auto-size, because it's set by `CreateComponentCore` after your constructor. But after you open the form again, this time, just your constructor will run and set the property to false. – Reza Aghaei Jan 20 '18 at 21:29

2 Answers2

5

The default values which you assign in constructor are respected in general. But for some cases the default values will be changed using designer, for example by the CreateComponentsCore method of ToolboxItem of the control.

The default value for AutoSize property for Label is false and you even don't need to override it or set it in constructor. But an AutoSizeToolboxItem has been assigned to Label which sets AutoSize to true when you drop an instance of Label on designer. To remove this behavior, it's enough to assign a new ToolboxItemto your control:

using System.ComponentModel;
using System.Drawing.Design;
using System.Windows.Forms;

namespace ClassLibrary1
{
    [ToolboxItem(typeof(ToolboxItem))]
    public sealed class CustomLabel : Label
    {
    }
}

Note 1: Just for your information, the ToolboxItem has a CreateComponentsCore method which you can use it to to some initialization tasks when dropping control on design surface.

Note 2 I should also add, the CreateComponentCore method will just run when you drop the component from toolbox to design surface. It describes why after dropping it on form, it's auto-size, because it's set by CreateComponentCore after your constructor. But after you open the form again, this time, just your constructor will run and set the property to false.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
2

The DefaultValueAttribute has no bearing on it: it mainly controls whether the property value should be serialized or not and whether the value should show in bold in the property editor window.

If you watch the designer code, initially it gets written out explicitly saving AutoSize as true. Apparently it saved the value because it doesnt match the value specified by the DefaultValue but it is saving the wrong value - apparently the base control hasnt gotten the update yet. Any change causes it to serialize the form again, this time with the correct value.

I dont know exactly why certain properties dont like being overridden and changed from the constructor, but there are a few that don't immediately take. AutoSize is one that gets handled thru SetStyle calls and/or thru some CommonProperties helper.

One way to set some of these is to implement ISupportInitialize to set the value after the control has been set from the designer properties. A simpler way is to override OnHandleCreated:

protected override void OnHandleCreated(EventArgs e)
{
    base.OnHandleCreated(e);
    base.AutoSize = false;
}

Seems to work as desired.

Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178
  • 3
    While your solution is valid, but you should know the default values which you assign in constructor are respected in general. But for some cases the default values will be changed using designer, for example by the `CreateComponentsCore` method of `ToolboxItem` of the control. The `AutoSize` property is one of those cases which is affected by `AutoSizeToolboxItem`. – Reza Aghaei Jan 20 '18 at 07:25