winformscustom-controlsdrop-down-menudesign-time-data

Custom Winforms ComboBox, hardcoded items also get added via Design tool


Greetings Overflow users,

I created a series of custom ComboBox controls, that should have hardcoded items at all times. The custom controls also have a GetEnum property, to return an Enum equivalent of the selected item.

The simple example of this control is the ComboBox_Boolean version.

public partial class ComboBox_Boolean : ComboBox
{
    public ComboBox_Boolean()
    {
        Initialize();
    }
    public void Initialize()
    {
        this.Items.Clear();
        foreach (string b in (new string[] { ">", ">=", "<=", "<", "=", "!="}))
            this.Items.Add(b);
        this.SelectedIndex = 0;
        this.DropDownStyle = ComboBoxStyle.DropDownList;
    }

    public BooleanType SelectedBoolean() { Get{//foo} Set{//foo}}
}
public Enum BooleanType {LT, LE, GE, GT, EQ, NE}

Now, this is fairly straightforward, and seems to work just fine.

What gets weird is, the Designer seems to pick up on this, and add these items again at the Designer level. For extra weirdness, it seems to add the items when I build or open the Design view for the first time. I haven't quite figured out the pattern.

Anyway, the point is, the Design code will eventually acquire this statement:

        this.myBooleanDropDown.Items.AddRange(new object[] {
        ">",
        ">=",
        "=",
        "<=",
        "<",
        "!=",
        ">",
        ">=",
        "=",
        "<=",
        "<",
        "!="});

This, of course, is rather annoying. My question has two parts:

1) Why is this happening?

2) How can I prevent it?

I tried overriding the this.Items property and making it private, or otherwise making it not work, but that gave an error. The only way I intend to interact with this custom control is via the SelectedBoolean property.


Solution

  • I would have to think very hard to explain exactly why the items show in the designer this way, but I think it is enough to know that it has to do with the fact that the code also runs at design time.

    The way to prevent this is putting your in an override of InitLayout which enables you to only run it when not in design mode (not all code in a control is DesignMode aware, but InitLayout is):

    protected override void InitLayout()
    {
      base.InitLayout();
      if (!DesignMode)
      {
        this.Items.Clear();
        foreach (string b in (new string[] { ">", ">=", "<=", "<", "=", "!=" }))
          this.Items.Add(b);
        this.SelectedIndex = 0;
        this.DropDownStyle = ComboBoxStyle.DropDownList;
      }
    }