2

I have a BaseForm that specifies several protected controls which are initialized in BaseForm.InitializeComponent(). I've made these controls protected so that I can access the values of dropdowns, etc, in my DerivedForm. Making these controls accessible to DerivedForm causes the Designer to include them in DerivedForm.InitializeComponent(), which resets them, thus undoing any additional work I've done in the BaseForm constructor.

Is there a way to access my BaseForm controls in DerivedForm, but not have them initialized a second time?

    public SettingsDialogBase(Settings settings)
    {
        InitializeComponent();

        // Additional work which initializes dropdowns, etc
        InitializeSettings();
    }

    public SettingsDialog(Settings settings) : base(settings)
    {
        InitializeComponent();
        // InitializeSettings() rendered useless on controls that are set to protected
        // because SettingsDialog.InitializeComponent() included them automatically
    }
Danielle
  • 472
  • 4
  • 20
  • Possible duplicate of [Windows Form inheritance](http://stackoverflow.com/questions/826425/windows-form-inheritance) – Ricardo Serra Mar 21 '17 at 18:24
  • Mmm I don't think so. Both my BaseForm and DerivedForm successfully call their own InitializeComponent() method. The problem is that the BaseForm constructor does additional work on the controls after InitializeComponent(), and because they are protected controls DerivedForm undoes all the work when it calls its own InitializeComponent() method. – Danielle Mar 21 '17 at 18:30
  • Remove `InitializeComponent()` from constructor of derived class – Fabio Mar 21 '17 at 19:14
  • My DerivedForm has components that are specific to it that need to be initialized.... – Danielle Mar 21 '17 at 19:27
  • Initialize components is not a magic method. It is normally generated in the form designer file but you are not required to have a designer file. you can put it all inline in the main .cs file if you like. If you must do things your way why not just write two versions of InitializeComponent and have each class call their own version? – Mike Cheel Mar 21 '17 at 20:20

2 Answers2

1

I've made these controls protected so that I can access the values of dropdowns

There's your problem.

Don't make those controls protected. Keep them private to the base class. Expose them to subclasses exactly as you would publicly: by wrapping access to the controls in public properties that allow access to only the aspects of those controls that need to be accessed.

For example:

class BaseForm : Form
{
    public string PromptText
    {
        get { return textBox1.Text; }
        set { textBox1.Text = value; }
    }

    public int SelectedIndex
    {
        get { return comboBox1.SelectedIndex; }
        set { comboBox1.SelectedIndex = value; }
    }

    // etc.
}

Note that if things like ComboBox uses e.g. enum values, you can make a property like SelectedValue instead, having the enum type and cast when returning from the comboBox1.SelectedValue property.

Note also that another way to approach this type of design issue is to author UserControl objects instead of forms, and use composition to build up the task-specific forms. This avoids inheritance altogether.

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • The majority of the fields I am attempting to access are ComboBox controls, so this will work just fine. I also found that adding [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] to other controls, like GroupBox, seems to prevent it from getting too crazy in the DerivedForm.InitializeComponent() – Danielle Mar 23 '17 at 11:47
0

BaseForm's implementation of InitializeSettings:

protected virtual void InitializeSettings(Settings settings)
{
    //initialization of settings
}

DerivedForm's implementation of InitializeSettings:

protected override void InitializeSettings(Settings settings)
{
    base.InitializeSettings(x);
    //reinitialization of settings
}

And call of InitializeSettings() in your DerivedForm's constructor will set your settings.

Okay, the goal was not clear for me.

If you want to have just 1 initialization of Settings, do not apply them in constructor. Basically, you should use the

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    //initialization of settings
}

The second way to solve the problem is to not even have parameterized constructor and to call InitializeSettings outside after creation of form by default constructor.

Perspicathir
  • 26
  • 1
  • 5
  • So my components still get initialized twice, and then the settings are initialized twice to compensate for it? I'm really looking for solution where initialization of components and settings is done once. Specifically, the BaseForm initializes its components and the DerivedForm initializes ONLY its components, and not those which are protected BaseForm components. – Danielle Mar 21 '17 at 19:30