Reputation: 3
I have a question regarding User Controls created with Visual Studio 2010.
Specifically, I have created a simple User Control extending the default Label .Net control. Using the Designer, I specified the BackColor of my User Control to "White" (note that my User Control does have an area of its own not occupied by any other control). After building the project, I used my control on a form of a second project under the same solution by dragging it from the toolbox.
After the placement of the control, I modified the very same property of my User Control and turned BackColor to "Red". I recompiled the entire solution (with project dependencies checked - user control project first and the dependent second project last). Subsequently, I created a second instance of my User Control on the form (by dragging it from the toolbox). Although this second instance appears with "Red" background as expected, the first instance persists with the "White" BackColor.
This is highly non-intuitive to me and I am wondering why? I expect ALL controls to adopt any changes made to the base class when the changes affect properties not overriden after their placement on the form. The only conclusion I managed to derive is that it has to do with VS generating the "designer.vb" code for the first instance of the control and NEVER regenerating it afterwards, even though the base user control has been altered and recompiled.
Any ideas ?
UPDATE: Thank you all for your answers! I would like to point out that setting the BackColor property was merely an example for illustrating my point. It appears to me that even if no properties at all are defined for my custom control during design time, VS generates a standard set of properties in the code behind( in addition to any explicit properties defined by the developer). Therefore, omitting the explicit specification of properties does not always tackle the problem (the default VS mechanism of setting properties in the designer.vb file). I believe the only way to address the issue once and for all, is to set property initialization code inside the control's New or Load method; not always a practical solution when a lot of initialization needs to be performed!
Upvotes: 0
Views: 2459
Reputation: 942438
This goes wrong because you haven't told the designer what the default value for the property is. So when you drop your custom label on a form, the designer generates this kind of code in the form's Designer.cs file:
this.myLabel1.AutoSize = true;
this.myLabel1.BackColor = System.Drawing.Color.Red; // <=== Here !
this.myLabel1.Location = new System.Drawing.Point(19, 22);
this.myLabel1.Name = "myLabel1";
this.myLabel1.Size = new System.Drawing.Size(52, 13);
this.myLabel1.TabIndex = 0;
this.myLabel1.Text = "myLabel1";
The marked statement ruins it. When you now change the default in the control class, any control that you've already dropped on any form is not going to change to that default color, the designer code overrides it.
You'll need to use the [DefaultValue] attribute to tell the designer about your default. Like this:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
class MyLabel : Label {
public MyLabel() {
this.BackColor = Color.Red;
}
[DefaultValue(typeof(Color), "Red")]
public override Color BackColor {
get { return base.BackColor; }
set { base.BackColor = value; }
}
}
Now the designer will omit the assignment and any change you make inside the control will be effective. The attribute syntax is clumsy, unfortunately you need to use a string.
Upvotes: 2
Reputation: 244991
The only conclusion I managed to derive is that it has to do with VS generating the "designer.vb" code for the first instance of the control and NEVER regenerating it afterwards, even though the base user control has been altered and recompiled.
This is the correct conclusion. You specifically told the designer to make the BackColor
of the first control white, and it obeyed by inserting code into the *.Designer.vb
file that sets the BackColor
property to white. It does this unconditionally so that it overrides whatever the default BackColor
property of the control is.
When you change the default BackColor
property of the control to red, this affects all new instances of the controls that are created, because they're still using the default property value. But it doesn't affect instances of the control for which you have explicitly overridden the value of that property.
As unintuitive as this behavior may seem to you, it's actually by design. If you want all instances of the control to inherit the default background color, then don't set the BackColor
property for individual instances of it.
To force a particular instance of the control to use the default background color, even if you have set it explicitly, right-click on the property in the Properties Window and select "Reset". In this case, the background of the first instance of the custom control should turn red as it inherits the default value for that particular property.
In response to your update, the problem is that the various control classes set their own default values (by themselves overriding them from their parent class, Control
). If you want to override those with new defaults for your custom control, you need to write code inside of the custom control class for that. You can't do it in the designer, because that affects only that particular instance of the custom control, not the entire class.
There are two things in particular you need to do. First, override the relevant property and set a default value using the DefaultValueAttribute
. Second, set the default values for the properties in the class's constructor.
Here's an example of a custom control that inherits from the default Label
control. I have versions of all the standard controls that basically just force the FlatStyle
property to FlatStyle.System
by default. The code is arbitrarily in VB.NET, but you should be able to convert it easily if C# is your preferred dialect.
Imports System.Windows.Forms
Imports System.ComponentModel
Imports System.Drawing
<ToolboxItem(True)> <ToolboxBitmap(GetType(ResFinder), "LabelEx.bmp")> _
<Description("A standard Windows label control for displaying static text and images.")> _
Public Class LabelEx : Inherits Label
''' <summary>
''' Gets or sets the flat style appearance of this label control.
''' </summary>
<DefaultValue(GetType(System.Windows.Forms.FlatStyle), "System")> _
Public Shadows Property FlatStyle As FlatStyle
'Set the default flat style to System
Get
Return MyBase.FlatStyle
End Get
Set(ByVal value As FlatStyle)
MyBase.FlatStyle = value
End Set
End Property
''' <summary>
''' Initializes a new instance of the LabelEx" class with default settings.
''' </summary>
Public Sub New()
MyBase.New()
'Set default property values
Me.FlatStyle = FlatStyle.System
End Sub
End Class
The only major exceptions to this general rule is if you want to change the defaults for the size or padding of the control. In this case, you should just override the protected DefaultSize
and DefaultPadding
properties; i.e.
''' <summary>
''' Gets the default Size of a ButtonEx control.
''' </summary>
Protected Overrides ReadOnly Property DefaultSize As Size
Get
Return New Size(88, 26)
End Get
End Property
''' <summary>
''' Gets the spacing, in pixels, around the image that is displayed on this button control.
''' </summary>
Protected Overrides ReadOnly Property DefaultPadding As Padding
Get
Return New Padding(7, 0, 0, 0)
End Get
End Property
In this case, you should not set the default values for the public properties in the constructor.
For more clues on how to write custom controls (and some useful controls!), you might check out the Windows Forms Aero library.
Upvotes: 2
Reputation: 31202
You're correct, the backcolor is defined in your form designer generated code.
If you really want to disable setting back color while still inheriting from Label, you can override the BackColor property and remove it from the properties tab of the designer :
[EditorBrowsable(EditorBrowsableState.Never)]
[Browsable(false)]
public override Color BackColor
{
get
{
return Color.Blue;
}
set
{
}
}
Upvotes: 0