Within the ASP.NET architecture, there are a variety of
kinds of server controls. There are controls that don't render any type of
user interface but that have an important function such as data source controls,
AJAX control extenders, etc. There are web or HTML controls that map to
existing HTML controls like the TextBox, CheckBox, and others.
There are more advanced controls that have additional
capabilities, such as template controls, or controls that their interface is
created from the template that is provided. There are data-bound controls that
render an interface based on the underlying data source, or validation controls
to validate user input.
These are the various types of controls that can be
created. The base class for all controls is the System.Web.UI.Control class,
which is often used for controls that don't render a user interface. For more
specific functionality, server controls in ASP.NET inherit from the
System.Web.UI.WebControls.WebControl class, which provides added capabilities
to server-control rendering.
For controls that consist of one or more child controls, the
CompositeControl class can be used. All of the child controls that make up the
interface are added to the Controls collection, which this control can directly
expose properties/methods of the children, grouping the entire multiple server
control logic into one logical unit. For data-bound controls, the
DataBoundControl and CompositeDataBoundControl classes define methods for
receiving a data source, performing the binding and rendering the final user
interface based on the data provided.
This article assumes you have an understanding of these
controls, and a basic understand of custom control development. However, if
you need more information, the following resources are helpful.
·
Developing
ASP.NET Server Controls Overview on MSDN
·
A
Crash Course on Creating Controls
Throughout the article, you will notice in the code segments
statements like the following: "this.DesignMode". Because some of the
code (like the CreateChildControls) method runs in the designer, there may be
some problems that come up in the designer. Wrapping certain code in an
"if" statement, with this as its conditional, would prevent those
errors from occurring. Plus, using this statement within code means that I
don't have to provide a custom designer, which saves some coding effort for the
time being.
Custom controls also have to check the EnableViewState
property within it, because the control has to run with or without ViewState
enabled, and will perform certain actions more when it is disabled, such as
data binding to a data source control. There is another option of using
ControlState instead, since it guarantees state storage for control values, but
you should only use this for critical data. You will also see the use of the
ViewState collection in many of the property definitions. Before returning an
object, the control must ensure the value exists within ViewState; returning a
value and converting it to the proper type without checking it first will raise
an exception.
Rendering occurs through the HtmlTextWriter class; not all
controls need to customize the rendering process, but when custom rendering is
needed, this class does the job. It has a Write() method to write whatever
text it needs to, but it also has a better process for writing HTML tags;
RenderBeginTag() and RenderEndTag() methods that allow you to dynamically
create the tag by passing in the tag name only. Any attributes that you want
to add to an element being rendered with RenderBeginTag() need to be added
before you call this method. That means all of the AddAttribute() and
AddStyleAttribute() definitions occur before RenderBeginTag() is called.
Controls also make use of attributes, but this will be
discussed later.