-1

A regular C# Windows Form looks like this (the non-designer code):

public partial class BaseForm : Form
{
    public BaseForm()
    {
        // v--- very important method, it is what initializes the form
        InitializeComponent();
    }

    public BaseForm(string title)
        : this() // chain with the main constructor
    {
        this.Text = title;
    }
}

Now let's create a derivative form:

public partial class EntityForm : BaseForm
{
    public EntityForm()
        : base()
    {
    }

    public EntityForm(Entity entity)
        : base(entity.Name)
    {
    }
}

This second form stops working properly. When InitializeComponent(); is called, it is done so in the context of BaseForm (since it is always defined as non-overrideable and private).

At a glance, a solution might be to have InitializeComponent(); in every constructor, however this means that it might be called several times, creating objects unnecessarily (because of constructor chaining). A solution to this could be to take it as a general not to call base constructors which sort of defeats the purpose of OOP.

What am I doing wrong? Any ideas?

Christian
  • 27,509
  • 17
  • 111
  • 155
  • 2
    Your code example shows `EntityForm` inheriting `Form`. Are you sure this is an _actual_ working code example? If not, please post [a good, _minimal_, _complete_ code example](https://stackoverflow.com/help/mcve) that reliably reproduces the problem. – Peter Duniho Jul 09 '15 at 05:31
  • Uh, my bad. Right you are. Fixed. – Christian Jul 09 '15 at 05:33
  • Not calling a base constructor isn't an option anyway. It's not clear what you mean by _"second form stops working properly"_, but I doubt frankly that it has anything to do with the form inheritance or the `InitializeComponent()` method. If `EntityForm` has an `InitializeComponent()` method, it _should_ call that in its constructor(s). Without a good code example, it's not possible to even know what you mean by "stops working properly", never mind offer a solution. – Peter Duniho Jul 09 '15 at 05:38
  • The above example should suffice now. To quote myself where the problem lies: *When InitializeComponent(); is called, it is done so in the context of BaseForm (since it is always defined as non-overrideable and private).* – Christian Jul 09 '15 at 05:54
  • _"The above example should suffice now"_ -- Since it is not a complete code example that reliably reproduces the problem, no. It does not suffice. As for the passage you quote, that makes no sense...there's only one object. What do you even mean by _"in the context of BaseForm"_? Yes, it executes the method declared in that class but so what? There's no reason that _should_ cause a problem. If it does, you've made a mistake, in the code you didn't bother to show. – Peter Duniho Jul 09 '15 at 06:00
  • 1
    Constructors don't have a return type. `public void` makes no sense. – Loathing Jul 09 '15 at 06:06
  • https://social.msdn.microsoft.com/Forums/vstudio/en-US/91985294-ce1d-4cde-adf3-b30455afad95/how-to-call-initializecomponent-in-a-sub-class might solve your problem. – Philip Stuyck Jul 09 '15 at 06:10
  • @Loathing Oops, my bad. Fixed. *@Peter* that is exactly the code flow the program is running. I don't understand why you can't see the problem, it is exactly as you described. Every form has its own **private** `InitializeComponent()` method. If the child class *only* runs the one defined in the base class (by constructor chaining) then the controls in the child won't be initialized. – Christian Jul 09 '15 at 07:11
  • I also think you have to take a look at visual inheritance. – Philip Stuyck Jul 09 '15 at 07:54

1 Answers1

1

A possible solution that is somewhat elegant is to not pass parameters to the constructor at all - that is, only let one parameterless constructor call InitializeComponent(), which is the default for any custom control. Then I'd need a second method that actually sets up the control. This method can be overridden as required.

Example fix for the original source:

public partial class BaseForm : Form
{
    public BaseForm()
    {
        InitializeComponent();
    }

    public virtual void Initialize(string title)
    {
        this.Text = title;
    }
}

public partial class EntityForm : BaseForm
{
    public EntityForm()
    {
        InitializeComponent();
    }

    public virtual void Initialize(Entity entity)
    {
        base.Initialize(entity.Name); // the 'base' keyword is somewhat redundant
    }
}
Christian
  • 27,509
  • 17
  • 111
  • 155