469,934 Members | 2,607 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,934 developers. It's quick & easy.

Control inheritance spoiled by Form designer.

The form designer adds unnecessary code to the section when using a
subclassed control.
I've reproduced this in VS.NET 2002 and VS.NET 2003 so it's pretty
fundamental.

Outline steps:
Create a VB project.
Create a subclass of a UI control, I used TextBox.
Add no code to the subclass.
Public Class Component1
Inherits System.Windows.Forms.TextBox
#Region " Component Designer generated code "
#End Region
End Class

Change the forecolour property only (Red in this example).
The designer adds code to the InitialiseComponent() method to set the new
forecolour.
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
'
'Component1
'
Me.ForeColor = System.Drawing.Color.Red
End Sub

Build it.

Create a VB windows form project.
Drag/drop a baseclass textbox.
Add reference to the DLL containing the control.
Add that to the toolbox.
Drag/drop a subclassed textbox.

All appears good.
But looking at the code it's not using inheritance !!

The form designer incorrectly (IMO) adds a line of code which duplicates the
code in the subclassed control's InitialiseComponent() which totally negates
the inheritance - I find this in the form's InitialiseComponent().

'Component11
'
Me.Component11.ForeColor = System.Drawing.Color.Red

If I distribute the control subclass as a separate assembly (dll) and then
update that dll, the compiled form has code that is hardwired to set the
colour of the instance of the control.
That's not right!
Because when I distribute a new version of the control with a different
forecolour, the code in the contorl's InitialiseComponent() might just as
well not be there - because the VB form has a line of code to set the colour
to that of the version of the component used at the time the form was
edited.
I can remove the offending code from the form's InitialiseComponent() and it
has no visual effect.
The colour is still as defined in the subclassed control.
I can change the control's forecolour, rebuild the dll and the form shows
the new forecolour.
There is still no offending code in the form InitialiseComponent()

Now we enter the twilight zone ...
In the form designer, if I move _either_ of the two textboxes, the offending
line of code reappears.
So, is this a known bug?
I don't want to have to put code in the subclassed control's Paint() method
for example, because that gets called far too often.

--

PAul
Nov 20 '05 #1
11 2063
I've now reproduced this in a C# form too, using the same VB subclass of
textbox, so it's pretty fundamental!

There is no reason as far as I can see that the form should have a copy of
the code from the subclasses control's InitialiseComponent() in the form's
InitialiseComponent() - because that overrides any change you may make in
the control class.
The form designer adds unnecessary code to the section when using a
subclassed control.
I've reproduced this in VS.NET 2002 and VS.NET 2003 so it's pretty
fundamental.

Outline steps:
Create a VB project.
Create a subclass of a UI control, I used TextBox.
Add no code to the subclass.
Public Class Component1
Inherits System.Windows.Forms.TextBox
#Region " Component Designer generated code "
#End Region
End Class

Change the forecolour property only (Red in this example).
The designer adds code to the InitialiseComponent() method to set the new
forecolour.
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() '
'Component1
'
Me.ForeColor = System.Drawing.Color.Red
End Sub

Build it.

Create a VB windows form project.
Drag/drop a baseclass textbox.
Add reference to the DLL containing the control.
Add that to the toolbox.
Drag/drop a subclassed textbox.

All appears good.
But looking at the code it's not using inheritance !!

The form designer incorrectly (IMO) adds a line of code which duplicates the code in the subclassed control's InitialiseComponent() which totally negates the inheritance - I find this in the form's InitialiseComponent().

'Component11
'
Me.Component11.ForeColor = System.Drawing.Color.Red

If I distribute the control subclass as a separate assembly (dll) and then
update that dll, the compiled form has code that is hardwired to set the
colour of the instance of the control.
That's not right!
Because when I distribute a new version of the control with a different
forecolour, the code in the contorl's InitialiseComponent() might just as
well not be there - because the VB form has a line of code to set the colour to that of the version of the component used at the time the form was
edited.
I can remove the offending code from the form's InitialiseComponent() and it has no visual effect.
The colour is still as defined in the subclassed control.
I can change the control's forecolour, rebuild the dll and the form shows
the new forecolour.
There is still no offending code in the form InitialiseComponent()

Now we enter the twilight zone ...
In the form designer, if I move _either_ of the two textboxes, the offending line of code reappears.
So, is this a known bug?
I don't want to have to put code in the subclassed control's Paint() method for example, because that gets called far too often.

--

PAul

Nov 20 '05 #2
"PAul Maskens" <pm******@mvps.org> schrieb
The form designer adds unnecessary code to the section when using
a subclassed control.
I've reproduced this in VS.NET 2002 and VS.NET 2003 so it's pretty
fundamental.
[...]


It is not an inheritance issue. The designer is not interested in the
inheritance hierarchy. The reason why it creates the code is that the
property value (red) is not equal to default value of the property.

See also (didn't read the whole article):
http://msdn.microsoft.com/library/en...ustcodegen.asp

quote: "...If the current value of a property matches that default value,
code is not generated."

--
Armin

How to quote and why:
http://www.plig.net/nnq/nquote.html
http://www.netmeister.org/news/learn2quote.html

Nov 20 '05 #3
> It is not an inheritance issue.
Becauase it prevents us using inheritance to define visual characteristics,
and redefine in a new release of the assembly containing the subclass, it is
an inheritance issue.
The designer is not interested in the inheritance hierarchy. Exactly, so the designer is breaking inheritcance.
The reason why it creates the code is that the property value (red)
is not equal to default value of the property. What were they smoking when they designed that, then?
quote: "...If the current value of a property matches that default value,
code is not generated."

So the question then is, how do I define the new value in my subclass as the
new default?

It's not a show stopper, but I've been using OO languages for ten years and
this is unbelievable.
Nov 20 '05 #4
"PAul Maskens" <pm******@mvps.org> schrieb
It is not an inheritance issue. Becauase it prevents us using inheritance to define visual
characteristics, and redefine in a new release of the assembly
containing the subclass, it is an inheritance issue.
The designer is not interested in the inheritance hierarchy.

Exactly, so the designer is breaking inheritcance.


The designer creates code. Neither it changes your controls nor derives new
controls from yours, consequently it is impossible that it brakes
inheritance.
The reason why it creates the code is that the property value
(red) is not equal to default value of the property.

What were they smoking when they designed that, then?


Why? How can the designer know that the constructor of your control already
sets the value? It would have to analyse the source code or your control.
Not possible. Or, it would have to create the following code:

if not c.forecolor.equals(color.red) then
c.forecolor = color.red
end if

Wouldn't make sense, too, as we both know.
quote: "...If the current value of a property matches that default
value, code is not generated."

So the question then is, how do I define the new value in my subclass
as the new default?


As mentioned in the linked article, there's the DefaultValue attribute:

<System.ComponentModel.DefaultValue(GetType(Color) , "Red")> _
Public Overloads Property ForeColor() As Color
Get
Return MyBase.ForeColor
End Get
Set(ByVal Value As Color)
MyBase.ForeColor = Value
End Set
End Property

Seems to work.

It's not a show stopper, but I've been using OO languages for ten
years and this is unbelievable.


IMO it is not related to OO and especially inheritance at all.
--
Armin

Nov 20 '05 #5
Thanks for sticking with me on this, Armin.

<System.ComponentModel.DefaultValue(GetType(Color) , "Red")> _
Public Overloads Property ForeColor() As Color
Get
Return MyBase.ForeColor
End Get
Set(ByVal Value As Color)
MyBase.ForeColor = Value
End Set
End Property

Ouch !!
That's incredibly complex!
I was hoping this would work:

Function ShouldSerializeForeColor() As Boolean
ShouldSerializeForeColor = false
End Function

Like the C# example in the article.

Quote:
But what if the default value is not a simple one or this needs to be done more dynamically? This is often the case for values that are inherited from other components such as a parent Control. The dynamic case can be handled by adding a method of a certain signature. Using the example above, the code would look like this:

private bool ShouldSerializeText()
{
return Text != "OK";
}
By adding a method of the name ShouldSerialize<Property Name>, the code generation engine can ask the component if it would like the value to be serialized.
I can't get that to work in my simple test.
So I'm doing something wrong.
Nov 20 '05 #6
> if not c.forecolor.equals(color.red) then
c.forecolor = color.red
end if Why does the designer effectively do just that?
True, in this case it's analysing the value of the property.

What it does is if the current colour of my control subclass is not the
default colour of the parentclass, it writes a line of code into the form's
InitializeComponent().
Logically it's doing something like this (if parentclass was a property of a
control subclass) in the designer.

if not c.corefolor.equals(c.parentclass.forecolor) then
' write following code to the form InitializeComponent()
me.c.foreColor = color.green
end if

It would have to analyse the source code or your control.

In this case it's analysing the property values.
Nov 20 '05 #7
"PAul Maskens" <pm******@mvps.org> schrieb
Thanks for sticking with me on this, Armin.

<System.ComponentModel.DefaultValue(GetType(Color) , "Red")> _
Public Overloads Property ForeColor() As Color
This should have been

public OVERRIDES property....
Get
Return MyBase.ForeColor
End Get
Set(ByVal Value As Color)
MyBase.ForeColor = Value
End Set
End Property

Ouch !!
That's incredibly complex!
Well, attaching an attribute is not complex, but you can not attach an
attribute to a derived member, so you have to override it to get a procedure
to attach an attribute to.
I was hoping this would work:

Function ShouldSerializeForeColor() As Boolean
ShouldSerializeForeColor = false
End Function

Like the C# example in the article.

Quote:
But what if the default value is not a simple one or this needs to be
done more dynamically? This is often the case for values that are
inherited from other components such as a parent Control. The dynamic
case can be handled by adding a method of a certain signature. Using
the example above, the code would look like this:

private bool ShouldSerializeText()
{
return Text != "OK";
}
By adding a method of the name ShouldSerialize<Property Name>, the
code generation engine can ask the component if it would like the
value to be serialized.


I learn many new things in this thread. :-) This works for me:

Private Function ShouldSerializeForeColor() As Boolean
Return (Not Me.ForeColor.Equals(Color.Red))
End Function

But, _in addition_ you have to override the ForeColor property:

Public Overrides Property ForeColor() As Color
Get
Return MyBase.ForeColor
End Get
Set(ByVal Value As Color)
MyBase.ForeColor = Value
End Set
End Property
Why? The ForeColor property is part of the TextBoxBase class. The designer
looks at the members of the same type that contains the property to be
serialized to find the ShouldSerialize* function. It does find it, but it's
derived from the Control class. So, the designer calls
Control.ShouldSerializeForeColor. To change this behavior, you have to
override the property. Consequently the designer looks for
ShouldSerializeForeColor in your derived class.

--
Armin

Nov 20 '05 #8
"PAul Maskens" <pm******@mvps.org> schrieb
if not c.forecolor.equals(color.red) then
c.forecolor = color.red
end if Why does the designer effectively do just that?


It does *not* create this code. I wrote "it would have to create...".
True, in this case it's analysing the value of the property.

What it does is if the current colour of my control subclass is not
the default colour of the parentclass, it writes a line of code into
the form's InitializeComponent().
Logically it's doing something like this (if parentclass was a
property of a control subclass) in the designer.

if not c.corefolor.equals(c.parentclass.forecolor) then
' write following code to the form InitializeComponent()
me.c.foreColor = color.green
end if


What is a corefolor? ;-)) Anyway, I currently can not follow you. I wanted
to say that the designer compares the forecolor to the color specified in
the DefaultValueAttribute. If not equal => code is generated.
It would have to analyse the source code or your control.

In this case it's analysing the property values.


I'm not sure if I understand you. What I'm trying to say is that the
designer does not know if you already set Forecolor = Red within the
constructor. Consequently the designer must generate the code that you don't
want to be created.
--
Armin

Nov 20 '05 #9
Do you have any idea why the ShouldSerialize<property>() method isn't
working?
Can you see any mistake in what I tried in VB?

Function ShouldSerializeForeColor() As Boolean
ShouldSerializeForeColor = false
End Function
I am trying to use this approach. Because it talks exactly about what we are
doing, with a value inherited from a parent control.
Quote:
But what if the default value is not a simple one or this needs to be done
more dynamically? This is often the case for values that are inherited from
other components such as a parent Control. The dynamic case can be handled
by adding a method of a certain signature. Using the example above, the code
would look like this:

private bool ShouldSerializeText()
{
return Text != "OK";
}
By adding a method of the name ShouldSerialize<Property Name>, the code
generation engine can ask the component if it would like the value to be
serialized.
Nov 20 '05 #10
"PAul Maskens" <pm******@mvps.org> schrieb
Do you have any idea why the ShouldSerialize<property>() method
isn't working?
Can you see any mistake in what I tried in VB?
It works for me. See my answer to your other message.
Function ShouldSerializeForeColor() As Boolean
ShouldSerializeForeColor = false
End Function


I would not always set it to false. If you change the Color to Green within
the designer, the setting won't be stored.

--
Armin

Nov 20 '05 #11
That's fine.
We don't want colour changes to be made in the designer.
We are using an ObjectMode proeprty which says what kind of control it is
(in our application) and that drives the setting of appropriate colours
depending on control and application state.
Yes, we're ignoring windows standards, which I don't think is such a good
thing.
But it emulates an existing application's UI.

We planned to do this in a root class layer, inheriting directly from the
base controls, so that we could apply comany-wide standards there. Then
lower layers can add application specializations if necessary.
Designer support for this is critical, so we can reissue the libraries
separately from the application.
Nov 20 '05 #12

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

1 post views Thread by Jason Hickey | last post: by
1 post views Thread by tjmii | last post: by
2 posts views Thread by Ray Cassick \(Home\) | last post: by
reply views Thread by Marc Gravell | last post: by
reply views Thread by Tony Johansson | last post: by
4 posts views Thread by iKiLL | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.