Attributes and Design-Time Support
Design-time support extensions are typically implemented in code that exists separately from the code for a component. A variety of attributes are used to associate design-time support providers with a type or an individual member of a type.
Attributes for Associating Design-Time Support
A DesignerAttribute associates a designer with a type. A TypeConverterAttribute associates a type converter with a type or type member. An EditorAttribute associates a UI type editor with a type or type member.
Attributes for Customizing Component Initialization
You can specify a default value for a property to be set when a component is loaded at design time by applying a DefaultValueAttribute to a property. A DefaultValueAttribute overrides a value set by component initialization code at design time, but the attribute does not override a value set by a designer.
Attributes for Customizing Property Browser Behavior
You can indicate whether a property or event should be listed in a property browser by applying a BrowsableAttribute to it. You can also modify the set of properties and events exposed to the property browser at design time using a designer that implements the IDesignerFilter interface. You can specify the category under which a property or event should be listed in the property browser by applying a CategoryAttribute to the property or event. You can specify a description to be displayed for a property or event in the property browser by applying a DescriptionAttribute to the property or event.
You can specify whether a property can be set only at design time by applying a DesignOnlyAttribute to the property. You can specify whether a property is read only or read/write at design time by applying a ReadOnlyAttribute to the property.
You can specify whether a property should be listed with its name in parentheses in the property browser by applying a ParenthesizePropertyNameAttribute to the property with a value of true.
You can specify whether a property that has nested, or child, properties should be notified when the value of a nested property changes by applying a NotifyParentPropertyAttribute to the nested property that should raise the notification.
You can specify whether the properties for a component should be refreshed, no properties should be refreshed, or the designer view should be repainted by applying a RefreshPropertiesAttribute with an appropriate RefreshProperties value to a property or event.
Attributes for Customizing Design-Time Serialization Behavior
You can specify whether the values of a property are serialized, or whether the values of a collection property are serialized, by applying a DesignerSerializationVisibilityAttribute with an appropriate DesignerSerializationVisibility enumeration value to the property.
You can specify that a type is serializable by applying a SerializableAttribute to the type. You can provide custom serialization by implementing the ISerializable interface or providing a custom serializer. For more information on Serialization, see Serializing Objects.
For more information about commonly used design-time attributes, see Design-Time Attributes for Components.
Applying Attributes
Design-time attributes are applied to properties, events, classes, and even to assemblies. The following code example shows attributes applied to a class and then to properties and events.
' The attribute is the element in angle brackets, and the parameters
' in the attribute syntax are arguments of the constructor
' of the attribute class.
'
' Attributes applied at the class level.
<DefaultEvent("ValueChanged"), _
DefaultProperty("Number")> _
Public Class MyControl
Inherits Control
...
' Attribute applied to a property.
<DefaultValue(False)> _
Public Shadows ReadOnly Property TabStop() As Boolean
...
End Property
' Attribute applied to a property.
<CategoryAttribute("Data")> _
Public ReadOnly Property Number() As Integer
...
End Property
' Attribute applied to an event.
<Description("Raised when the Value displayed changes.")> _
Public Event ValueChanged As EventHandler
...
End Class
[C#]// The attribute is the element in brackets, and the parameters in
// the attribute syntax are arguments of the constructor
// of the attribute class.
//
// Attributes applied at the class level.
[DefaultEvent("ValueChanged")]
[DefaultProperty("Number")]
public class MyControl : Control {
...
// Attribute applied to a property.
[DefaultValue(false)]
public new bool TabStop {...
}
// Attribute applied to a property.
[CategoryAttribute("Data")]
public int Number {...}
// Attribute applied to an event.
[Description("Raised when the Value displayed changes.")]
public event EventHandler ValueChanged;
}
By convention, attribute classes are named AttributeNameAttribute. The System.ComponentModel namespace contains many base attribute classes.
Design-Time Attributes and Inheritance
When you derive a component or control from a base component that has design-time attributes, your component inherits the design-time functionality of the base class. If the base functionality is adequate for your purposes, you do not have to reapply the attributes. However, you can override attributes of the same type or apply additional attributes to the derived component. The following code fragment shows a custom control that overrides the Text property inherited from Control by overriding the BrowsableAttribute attribute applied in the base class.
Public Class MyControl
Inherits Control
' The base class has [Browsable(true)] applied to the Text property.
<Browsable(False)> _
Public Overrides Property [Text]() As String
...
End Property
...
End Class
[C#]public class MyControl : Control {
// The base class has [Browsable(true)] applied to the Text property.
[Browsable(false)]
public override string Text {...}
...
}
Applying a Type Converter, UI Type Editor, or Designer Attribute
To associate a design-time support provider with a type or type member, apply the appropriate type of attribute on the line above the class declaration or member declaration. The following code example shows a TypeConverterAttribute applied to a type.
<TypeConverter(GetType(MyColorConverter)), _
Editor(GetType(MyColorEditor), GetType(UITypeEditor))> _
Structure MyColor
...
End Structure
[C#][ TypeConverter(typeof(MyColorConverter))]
[ Editor(typeof(MyColorEditor), typeof(UITypeEditor))]
struct MyColor {...}
If the type of a property does not have a type converter or UI type editor associated with it, or if you want to override the default type converter or UI type editor associated with the type of a property, you can apply an attribute to the property itself. To associate a type converter with a property, apply a TypeConverterAttribute to the property declaration, as shown in the following code example.
<TypeConverter(GetType(PointConverter))> _
Public Property MyLocation() As Point
...
End Property
[C#][ TypeConverter(typeof(PointConverter))]
public Point MyLocation {...}
To associate a UI type editor with a property, apply an EditorAttribute to the property, as shown in the following code example.
<Editor(GetType(FlashTrackBarDarkenByEditor), _
GetType(UITypeEditor))> _
Public Property DarkenBy() As Byte
...
End Property
[C#][ Editor(typeof(FlashTrackBarDarkenByEditor), typeof(UITypeEditor))]
public byte DarkenBy {...}
A designer can be associated with a type, but not a property. To associate a designer with a type, apply a DesignerAttribute directly above the class declaration, as shown in the following code example.
<Designer(GetType(HelpLabel.HelpLabelDesigner))> _
Public Class HelpLabel
Inherits System.Windows.Forms.Control
Implements System.ComponentModel.IExtenderProvider
...
End Class
[C#] [Designer(typeof(HelpLabel.HelpLabelDesigner))]
public class HelpLabel : System.Windows.Forms.Control, System.ComponentModel.IExtenderProvider {...}
Note In the above examples, the constructors for the TypeConverterAttribute, EditorAttribute, and DesignerAttribute classes accept System.Type objects as their arguments. This form of constructor for these attributes works if the type is in the same assembly as the design-time classes. If the design-time classes are in a different assembly, then a different form of the attribute constructor (called the assembly-qualified format) is needed, as shown in the following code example.
<Designer("System.Windows.Forms.Design.DocumentDesigner, System.Design")> _
Public Class MyForm
Inherits Form
...
End Class
[C#][Designer("System.Windows.Forms.Design.DocumentDesigner, System.Design")]
public class MyForm : Form {...}
Assembly-Level Design-Time Attribute
ASP.NET provides an assembly-level attribute (System.Web.UI.TagPrefixAttribute) that enables a control developer to specify a tag prefix for an ASP.NET control. The tag prefix is automatically injected by Visual Studio .NET in the Register directive for the control, so that the control can be used declaratively on the page with the pre-specified tag prefix (<tagprefix:controlname ... runat = server /> ).
Note The TagPrefixAttribute works only in visual designers. If you author ASP.NET pages using a text editor such as Notepad, you need to specify the tag prefix and the namespace yourself in the Register directive for the control.
The following code example shows how to apply the TagPrefixAttribute. The first argument to the attribute's constructor specifies the namespace and the second specifies the tag prefix.
<assembly: TagPrefix("SimpleControls", "simple")>
Namespace SimpleControls
<Designer("SimpleControl.Design.SimpleDesigner, SimpleControl")> _
Public Class SimpleControl
Inherits System.Web.UI.WebControls.WebControl
...
End Class
End Namespace
[C#][ assembly:TagPrefix("SimpleControls", "simple") ]
namespace SimpleControls {
[
Designer("SimpleControl.Design.SimpleDesigner, SimpleControl")
]
public class SimpleControl : System.Web.UI.WebControls.WebControl {...}
}
See Also
Enhancing Design-Time Support | Implementing a Type Converter | Implementing a UI Type Editor | Custom Designers