Forms inheritance and templates

  • Thread starter Thread starter Mark Baldwin
  • Start date Start date
M

Mark Baldwin

I have a project that brings up numerous forms that all follow the same
format both in the way they look and work. I need to find a solution that
saves me time recreating a form from scratch and at the same time allow me
to make UI changes that then apply to forms that have already been created.

As I understand it, templates allow me to create a base form but any changes
to that base form won't be reflected in existing forms - only new ones.

Inheritance seems ideal but once the form is setup, for instance with a
header panel and a tabcontrol then I can longer modify these controls by
adding tabs or text/buttons to the panel.

It seems that neither solution will work for me - am I missing something?
 
I have a project that brings up numerous forms that all follow the same
format both in the way they look and work. I need to find a solution that
saves me time recreating a form from scratch and at the same time allow me
to make UI changes that then apply to forms that have already been created.

As I understand it, templates allow me to create a base form but any changes
to that base form won't be reflected in existing forms - only new ones.

Inheritance seems ideal but once the form is setup, for instance with a
header panel and a tabcontrol then I can longer modify these controls by
adding tabs or text/buttons to the panel.

It seems that neither solution will work for me - am I missing something?

Change the Modifiers property of the child controls to Protected. That
will allow them to be modified in the inherited classes.

However, beware that a number of the nice new container controls added
in 2.0 (TableLayoutPanel, etc.) are not editable in the designer in
inherited classes.
 
Hi Mark,

Is your project a WinForm application project or a WPF application project?

You have mentioned "templates" and "header panel" in your post, so it seems
that your project is a WPF application project.

By "templates", do you mean ControlTemplate?

I'm performing research on this issue and will get the result back to you
ASAP. I appreciate your patience!

Sincerely,
Linda Liu
Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
in response to original post by Mark Baldwin :

"Inheritance seems ideal but once the form is setup, for instance with a
header panel and a tabcontrol then I can longer modify these controls by
adding tabs or text/buttons to the panel on inherited form :"

Jack Jackson wrote :

"Change the Modifiers property of the child controls to Protected. That will
allow them to be modified in the inherited classes."

I had once thought about trying this, but ... uhhh ... lost my nerve,
feeling that there might be some strange gotchas down the line if I did
something like this : create a typical Windows Form application, go into the
main form's designer window; change the control variables from 'private to
'protected.

If you do this, you will find ... in the designer view of the inherited form
.... you can't delete the inherited controls from your base form (which is
fine with me), but you certainly can ... for example, in the Form Load event
for your inherited form ... delete the controls you don't want
programmatically. And of course you can add new controls in the designer.

I still wonder if there might be some "unknown consequences" of making
changes like this in the modifiers of the base form's designer control
variables. One obvious "consequence" is the fact that if you add new
controls, or change the controls in the base form, then you may have to
modify the inherited forms. I could see that adding an additional burden in
a team programming situation where other people were consumers of your
control/forms. Maybe this is what "templates" in VS are for ? Or, you could
make the argument that a design where you end up deleting controls you've
inherited is poor design : what should have been done is first define a base
class that implements controls all inherited forms will need and cannot
modify (and these stay as 'private), then have inherited forms add their own
unique controls as needed.

But in the real world ... you might well want to modify some complex menu
structure on the base form in an inherited form, I think.

thanks for your comments !

best, Bill
 
Mark and Jack,

Let me add one further comment on this topic :

An inherited form also inherits the private event-handler definitions of its
parent WinForms controls which have been "hooked up" at design time : even
though the code procedures called by the Event Handling mechanism are
defined as private : they will be called from your inherited form if you
leave the default parent's form event-handlers in place !

In my opinion, that way lies madness :)

So if you were re-using a control on the inherited form, and you added an
event-handler of your own using the standard += method; both your event
handler and the parent's form event handler are going to be called. And if
you examine the value "this" inside the parent form's private procedure
called by the event handler, you'll find it will vary depending on whether
the inherited form is firing or the parent form is firing.

You might think you could clear away the Parent form's existing event
handler in the inherited Form, but :

base.whatEverControl.Events

Is not accessible in the inherited form. And neither is the private
procedure wired to the Parent form's event handler, so you can't use -= to
remove it. I am sure one of our "gurus" is going to "weigh in" shortly with
an elegant technique for doing this :) Of course you can OMIT wiring up an
event handler in the Parent form and ONLY wire it up in the inherited form,
but then you are still, imho, wading into complexity which may come back to
haunt you in terms of code maintenance, what other people may do if they are
using a component using these methods, etc.

While the behavior of event dispatching in this context is, of course,
consistent with .NET, these "complications" were what led me to conclude
that using inherited forms ... where I would ever want to remove or disable
controls or events in the inherited forms ... were not good code practices.

best, Bill
 
in response to original post by Mark Baldwin :

"Inheritance seems ideal but once the form is setup, for instance with a
header panel and a tabcontrol then I can longer modify these controls by
adding tabs or text/buttons to the panel on inherited form :"

Jack Jackson wrote :

"Change the Modifiers property of the child controls to Protected. That will
allow them to be modified in the inherited classes."

I had once thought about trying this, but ... uhhh ... lost my nerve,
feeling that there might be some strange gotchas down the line if I did
something like this : create a typical Windows Form application, go into the
main form's designer window; change the control variables from 'private to
'protected.

I did not suggest that you modify the designer file. I suggested that
you change the Modifier property of the objects in the Property
window.
 
Mark and Jack,

Let me add one further comment on this topic :

An inherited form also inherits the private event-handler definitions of its
parent WinForms controls which have been "hooked up" at design time : even
though the code procedures called by the Event Handling mechanism are
defined as private : they will be called from your inherited form if you
leave the default parent's form event-handlers in place !

In my opinion, that way lies madness :)

Not at all. The inherited form may have no interest in some of the
events handled by the base class - it wants the base class event
handling to occur. To arbitrarily not service any event handlers in
the base class just because a form is inherited seems like madness to
me.
So if you were re-using a control on the inherited form, and you added an
event-handler of your own using the standard += method; both your event
handler and the parent's form event handler are going to be called. And if
you examine the value "this" inside the parent form's private procedure
called by the event handler, you'll find it will vary depending on whether
the inherited form is firing or the parent form is firing.

You might think you could clear away the Parent form's existing event
handler in the inherited Form, but :

base.whatEverControl.Events

Is not accessible in the inherited form. And neither is the private
procedure wired to the Parent form's event handler, so you can't use -= to
remove it. I am sure one of our "gurus" is going to "weigh in" shortly with
an elegant technique for doing this :) Of course you can OMIT wiring up an
event handler in the Parent form and ONLY wire it up in the inherited form,
but then you are still, imho, wading into complexity which may come back to
haunt you in terms of code maintenance, what other people may do if they are
using a component using these methods, etc.

Usually when you use inheritance you are trading some level of
obfuscation (by hiding code in various levels of inheritance) for not
duplicating code. I think by careful documentation and thought about
what functionality belongs in what class the result is much better
than not using inheritance.
While the behavior of event dispatching in this context is, of course,
consistent with .NET, these "complications" were what led me to conclude
that using inherited forms ... where I would ever want to remove or disable
controls or events in the inherited forms ... were not good code practices.

best, Bill

If inherited classes need to remove controls from the base class, then
I suggest that those controls should not be in the base class.

If you wire up an event in a base class, then all inherited classes
should use that event as defined in the base class.

If you want inherited classes to be able to optionally use the event
behavior of the base class, then you need to wire up the event in a
way that allows the inherited classes to make that choice. The way I
do this is to copy what the .NET framework does.

Suppose my base class has an Edit button. In the base class I have a
handler for the Edit button Click event that calls a "Protected
Overridable Sub OnEditClick()" method. In that method is the base
class code to handle the event. If an inherited class wants different
behavior, it overrides the method.
 
Jack Jackson wrote :

"I did not suggest that you modify the designer file. I suggested that you
change the Modifier property of the objects in the Property window."

Same result either way : code modified in the Designer.cs file by search
and replace (for speed) will, of course, change the Modifiers property value
seen in the Properties facility. If you have a very complex collection of
controls, some of which you want Protected, and some of which you wish to
remain Private, doing a select-all in the Design view and changing all the
objects to Protected means you will need to edit the Modifier value for some
of the controls after that.

This to me is a very minor point, a digression really, compared to the other
issues I raised.

best, Bill
 
Jack Jackson wrote :

"Not at all. The inherited form may have no interest in some of the events
handled by the base class - it wants the base class event handling to occur.
To arbitrarily not service any event handlers in the base class just because
a form is inherited seems like madness to me."

I think you have not quite understood my comments. We probably agree more
than you think : I would say any inherited form that for some reason doesn't
use any major part of its "parent's" functionality and events is poor
design. I bet you, like me, have ended up re-designing forms so that a first
prototype form, from which other forms have inherited, ends up being
"forked" so that it becomes two form classes : one of which is the core
functionality, objects, and events which all inherited forms use, and
another which adds some additional features that all its descendants will
use. I've even used (gasp) the Templates facility once in a while to avoid
doing this.

"Usually when you use inheritance you are trading some level of obfuscation
(by hiding code in various levels of inheritance) for not duplicating code.
I think by careful documentation and thought about what functionality
belongs in what class the result is much better than not using inheritance."

Here we are in complete agreement :) And very eloquently stated, I might
add ! My objection is not to the core idea of event broadcasting which is
one of the most wonderful things in .NET, but to the sticky wickets I have
gotten into using inherited forms. I would argue that inherited forms are
appropriate in some cases (top-down design scenarios, particularly), and
very potentially deadly in other scenarios (like prototyping).

"If inherited classes need to remove controls from the base class, then I
suggest that those controls should not be in the base class.

If you wire up an event in a base class, then all inherited classes should
use that event as defined in the base class.

If you want inherited classes to be able to optionally use the event
behavior of the base class, then you need to wire up the event in a way that
allows the inherited classes to make that choice. The way I do this is to
copy what the .NET framework does.

Suppose my base class has an Edit button. In the base class I have a
handler for the Edit button Click event that calls a "Protected Overridable
Sub OnEditClick()" method. In that method is the base class code to handle
the event. If an inherited class wants different behavior, it overrides the
method."

Your comments are eloquent and interesting, and appreciated. The last time I
tried (in C#) to implement this by making the procedure in the base class
public virtual, and the implementation in the inheriting class public
override , I was able to avoid calling the base class event, but my button
event handler was called twice for unknown reasons ! However, I was not
using the level of indirection you have described in your example (for which
I do not know off the top of my head the equivalent in C#) : perhaps therein
lies the rub.

It is good to continually re-evaluate what one assumes ! But I remain
convinced that inherited forms in any circumstance where usage is not 100%
consistent with the base class they inherit from ... and only ADDS
additional controls and functionality ... is a sticky wicket and liable to
distract me in real world development.

thanks, Bill
 
Thanks for you comments guys. I struggle to see any real advantage to
templates for forms, it seems to be "sold" as a way to keep a familiar look
and feel to the app and allow quick creation of forms but in reality the
familiar look and feel cannot be changed easily once you have created dozens
of forms from the template since changing the template has no effect on
"derived" forms whereas with inherited forms it does.

I have hit on a nice problem that highlights what Jack is saying about using
inheritance correctly and avoiding having the delete controls. If you have a
base form with a TabControl that has one tab that is common to all derived
forms, then in the derived form you add a specific tab - the derived tab
will always appear first and you can't get it to appear in any other order.
I suspect this is because the base class controls (ie tabs) are created
before the derived class controls and the tabs in the tab control are
ordered as they are created. You can delete these tabs in the derived forms
load method and then recreate them buts its messy code and your just making
more work for yourself, something derived forms are there to solve.
 
Thanks for you comments guys. I struggle to see any real advantage to
templates for forms, it seems to be "sold" as a way to keep a familiar look
and feel to the app and allow quick creation of forms but in reality the
familiar look and feel cannot be changed easily once you have created dozens
of forms from the template since changing the template has no effect on
"derived" forms whereas with inherited forms it does.

I have hit on a nice problem that highlights what Jack is saying about using
inheritance correctly and avoiding having the delete controls. If you have a
base form with a TabControl that has one tab that is common to all derived
forms, then in the derived form you add a specific tab - the derived tab
will always appear first and you can't get it to appear in any other order.
I suspect this is because the base class controls (ie tabs) are created
before the derived class controls and the tabs in the tab control are
ordered as they are created. You can delete these tabs in the derived forms
load method and then recreate them buts its messy code and your just making
more work for yourself, something derived forms are there to solve.

The TabPages are displayed in the order they appear in the
TabControl's TabPages collection. If you can't change the order at
design time, you can do it at runtime by removing and re-adding the
TabPages in the desired order.
 
Back
Top