The server extender's definition looks like the following
skeleton. Note the various uses of attributes.
Listing 1
[assembly: System.Web.UI.WebResource(
"Nucleo.Web.ButtonControls.ButtonEnabledExtender.js", "text/javascript")
]namespace Nucleo.Web.ButtonControls
{
[TargetControlType(typeof(IButtonControl)), ClientScriptResource(
"Nucleo.Web.ButtonControls.ButtonEnabledExtender",
"Nucleo.Web.ButtonControls.ButtonEnabledExtender.js")]
public class ButtonEnabledExtender: ExtenderControlBase
{
..
}
}
In the AJAX Control Toolkit API there are two main base
classes for developing custom controls: ExtenderControlBase and
ScriptControlBase. The ExtenderControlBase class is used in this example
because we are building an extender. For all extenders, these controls have a TargetControlID
property; this property is linking the extender to the server control (and
eventually underlying HTML element when it is rendered) that the extender control
extends through JavaScript. The TargetControlType attribute is used to limit
what type the controls can be.
Each server component has a server class (.cs or .vb) file
and a JavaScript (.js) file. The WebResource and ClientScriptResource
attributes map the server class to the javascript file and link the two
together. The deployment model with custom AJAX controls is that JavaScript
files are marked as embedded resources in Visual Studio to the client class
that it represents. These files are later extracted using the framework
components; no work is necessary for this on your part.
Moving along, to how easy the describing process is, the
following properties and event handlers are illustrated below. I will start by
illustrating the properties.
Listing 2
[ExtenderControlProperty, ClientPropertyName("isEnabledInitially")]
public bool IsEnabledInitially
{
get
{
return base.GetPropertyValue < bool > ("IsEnabledInitially", true);
}
set
{
base.SetPropertyValue < bool > ("IsEnabledInitially", value);
}
}
[ExtenderControlProperty, ClientPropertyName("receiverControlID"),
IDReferenceProperty(typeof(Control))]
public string ReceiverControlID
{
get
{
return base.GetPropertyValue < string > ("ReceiverControlID", null);
}
set
{
base.SetPropertyValue < string > ("ReceiverControlID", value);
}
}
The ExtenderControlProperty attribute maps the server
control properties to a property in the client component; otherwise, a
client-side error will be thrown if there is an invalid mapping. The
ClientPropertyName attribute specified the name of the property on the client
side if different than the property on the server-side. At runtime, the server
will push down the initial values it defines to the client component.
One other important attribute to note is if you have any
properties that reference another control (for both extenders and controls),
the IDReferenceProperty allows for proper retrieval of the ClientID at
description time.
For this extender, only one event is needed.
Listing 3
[ExtenderControlEvent, ClientPropertyName("enabledStatusChanged")]
public string OnClientEnabledStatusChanged
{
get
{
return base.GetPropertyValue < string > ("OnClientEnabledStatusChanged",
null);
}
set
{
base.SetPropertyValue < string > ("OnClientEnabledStatusChanged", value);
}
}
This event allows an ASPX page to provide the name of a
JavaScript method as an event handler, which gets called whenever an event is
raised on the client side (more on this soon). At runtime, the name of this
method has to be a valid JavaScript routine name, which will get called when
the event is fired from the client component.
One other note: The GetPropertyValue and SetPropertyValue
generic methods read/write data to/from ViewState; they are simply helper
methods for this process. That is all from the server component. That is all
the code that is needed at the moment to setup our ButtonEnabledExtender
control. It is that simple; the only item remaining is the client component.