ControlFreak
LANGUAGES:
VB.NET | C#
ASP.NET
VERSIONS: 3.5
Create Control Extenders
Using Visual Studio 2008, ASP.NET 3.5, and AJAX
By Steve C. Orr
This month, you ll learn to use some of the exciting new
control development features of Microsoft s latest cutting-edge development
tools to create your own AJAX
controls and extenders. Let s get started ...
What s in Visual Studio 2008?
Visual Studio 2008 should be released around the time you
read this article. Visual Studio 2008 includes the .NET Framework version 3.5,
which includes ASP.NET version 3.5. ASP.NET 3.5 includes ASP.NET AJAX
(codenamed Atlas), which was previously available as a separate downloadable
add-on to the preceding version of ASP.NET (version 2.0.)
If you ve been using ASP.NET 2.0 AJAX,
then you re aware it required a significant number of additions to the
web.config file. These web.config settings are now included by default in all
new ASP.NET projects created with Visual Studio 2008, so there is no need to
add them manually. However, a ScriptManager control is still required on every Web
form that wishes to utilize AJAX
capabilities.
You may have also heard of the ASP.NET AJAX Control
Toolkit. That open source project is not included with Visual Studio 2008. It
is still a freely downloadable add-on. The Control Toolkit is not needed, used,
or referenced by any of the code in this article.
Controls vs. Extenders
Microsoft s ASP.NET AJAX provides the ability to easily
create your own AJAX-compatible controls and control extenders. An ASP.NET AJAX
Server Control is similar to the standard old ASP.NET Server Control, but it
adds client-side features and capabilities based on Microsoft s AJAX
framework.
A Control Extender is a non-visual control that extends
the capabilities of another control. One thing that all control extenders have
in common is a property named TargetControlID, which is intended to reference a
specific instance of the control type that it is extending. The ASP.NET AJAX
Server Control Extender we ll create in this article extends the classic
ASP.NET TextBox control with the ability to restrict its input to numeric
characters only. To do this, it will utilize Microsoft s AJAX
framework.
ASP.NET AJAX Server Controls inherit from the new
ScriptControl class, while ASP.NET AJAX Server Control Extenders inherit from
the nearly identical ExtenderControl class. The ScriptControl class (which
inherits from WebControl) enables a number of AJAX-related functions. For
example, it verifies that a ScriptManager control exists on the page. The
ScriptControl class implements the IScriptControl interface.
In slight contrast, the ExtenderControl class inherits
from the Control class, and implements the IExtenderControl interface. The
IExtenderControl interface is virtually identical to the IScriptControl
interface; they both define two functions: GetScriptDescriptors and
GetScriptReferences.
The GetScriptDescriptors method is used to supply a list
of related JavaScript files. Similarly, the GetScriptReferences method is used
to supply a list of ScriptReference objects that represent each of those
scripts. Both the ScriptControl and the ExtenderControl classes use these
methods to ensure exactly one reference to each JavaScript file is output to
the page s HTML during the render event.
Because of the similarities between the ScriptControl and
ExtenderControl classes, the process of creating a basic AJAX Server Control is
virtually identical to the process of creating a basic AJAX Server Control
Extender. Once you ve learned how to create one, you ve essentially learned how
to create both.
So, let s put all this theory to work and create an AJAX
Server Control Extender that limits textbox entry to decimal characters only.
Create a Control Extender
To create our numeric textbox control extender using
Visual Studio 2008, choose the ASP.NET AJAX Server Control Extender template
from the Web section of the Visual Studio 2008 New Project dialog box, as shown
in Figure 1. We ll name this new numeric textbox extender project with the
abbreviated title NumTextExt.
Figure 1: Visual Studio 2008
provides several new project templates, including the ASP.NET AJAX Server
Control Extender template selected here.
After clicking OK on the New Project dialog box, Visual
Studio automatically creates a new project with two notable files in it:
ExtenderControl1.vb, and ClientBehavior1.js. These files contain significant
amounts of boilerplate code that you d otherwise have to type in manually if
you weren t using Visual Studio 2008. The contents of ExtenderControl1.vb are
listed in Figure 2A. It shows examples of the GetScriptDescriptors and
GetScriptReferences methods of the previously mentioned IScriptControl and
IExtenderControl interfaces.
<TargetControlType(GetType(TextBox))> _
Public Class NumTextExt
Inherits ExtenderControl
Protected Overrides Function GetScriptDescriptors( _
ByVal targetControl As
System.Web.UI.Control) _
As IEnumerable(Of
ScriptDescriptor)
Dim descriptor As New _
ScriptBehaviorDescriptor("NumTextExt.ClientBehavior1", _
targetControl.ClientID)
Dim descriptors As New
List(Of ScriptDescriptor)
descriptors.Add(descriptor)
Return descriptors
End Function
' Generate the script reference
Protected Overrides Function GetScriptReferences() _
As IEnumerable(Of
ScriptReference)
Dim scriptRef As New _
ScriptReference("NumTextExt.ClientBehavior1.js", _
Me.GetType().Assembly.FullName)
Dim scriptRefs As New
List(Of ScriptReference)
scriptRefs.Add(scriptRef)
Return scriptRefs
End Function
End Class
Figure 2A: This
boilerplate VB code is automatically generated by Visual Studio 2008 when you
choose the new project template highlighted in Figure 1. The C# version is
listed in Figure 2B.
It should be noted that if the ASP.NET AJAX Server Control
template is chosen from the Visual Studio New Project dialog box shown in
Figure 1 instead of ASP.NET AJAX Server Control Extender, the initial project
output is nearly identical. In a server control project, line 1 of Figure 2A
would be gone because a standard server control doesn t extend other controls. The
only other difference in the generated boilerplate code is that a server
control inherits from ScriptControl instead of ExtenderControl. Everything else
is functionally identical, including the contents of the JavaScript file
included in the project.
I made only two edits to the boilerplate
ExtenderControl1.vb file listed in Figure 2A; one on each of the first two
lines. I changed the default word Control to TextBox on the first line (this
specifies that the control extender is intended to extend only TextBox controls).
I also changed the name of the class on line 2 to NumTextExt from its generic
default name of ExtenderControl1 (just to be more descriptive).
namespace NumTextExtCS
{
[
TargetControlType(typeof(Control))
]
public class NumTextExt
: ExtenderControl
{
Public
ExtenderControl1()
{
//
// TODO: Add
constructor logic here
//
}
protected override
IEnumerable<ScriptDescriptor>
GetScriptDescriptors(Control targetControl)
{
ScriptBehaviorDescriptor descriptor = new
ScriptBehaviorDescriptor(
"NumTextExt.ClientBehavior1",
targetControl.ClientID);
yield return
descriptor;
}
// Generate the
script reference
protected override
IEnumerable<ScriptReference>
GetScriptReferences()
{
yield return new
ScriptReference("NumTextExt.ClientBehavior1.js",
this.GetType().Assembly.FullName);
}
}
}
Figure 2B: This is
the C# equivalent of the code listed in Figure 2A.
The rest is all boilerplate code that you may never need
to edit. It simply ensures that the extender control s related JavaScript file (ClientBehavior1.js)
is properly referenced in the project as an embedded WebResource. If you wanted
to include additional JavaScript files, this is where you d do it.
Figure 3 shows the boilerplate JavaScript code generated
for ClientBehavior1.js. It s not critical that you understand every detail of
this script, because it is mostly just wiring things up as needed to work with
Microsoft s client-side AJAX
framework. The most significant lines are commented.
/// <reference name="MicrosoftAjax.js"/>
Type.registerNamespace("NumTextExt");
NumTextExt.ClientBehavior1 = function(element)
{
NumTextExt.ClientBehavior1.initializeBase(this,[element]);
}
NumTextExt.ClientBehavior1.prototype = {
initialize: function()
{
NumTextExt.ClientBehavior1.callBaseMethod(this,
'initialize');
// Add custom
initialization here
},
dispose: function() {
//Add custom
dispose actions here
NumTextExt.ClientBehavior1.callBaseMethod(this,
'dispose');
}
}
NumTextExt.ClientBehavior1.registerClass
('NumTextExt.ClientBehavior1', Sys.UI.Behavior);
if (typeof(Sys) !== 'undefined')
Sys.Application.notifyScriptLoaded();
Figure 3: This is
the boilerplate ClientBehavior1.js code automatically generated by Visual
Studio 2008 when the new project template highlighted in Figure 1 is chosen.
Line 1 is not strictly necessary. It merely lets Visual
Studio know that AJAX will be used.
This enables Visual Studio 2008 s greatly enhanced JavaScript IntelliSense
capabilities to spring to life when editing the text of this file.
You should also take note of the other two comments in
this file, which point out key locations where you ll need to insert custom
JavaScript constructor and destructor code for the control extender. This is
the constructor code I ve added under the Add custom initialization here
comment in Figure 3:
var e = this.get_element();
this._keyPressDelegate =
Function.createDelegate(this,this._onKeyPressDelegate);
$addHandler(e,"keypress",this._keyPressDelegate);
The above code wires up the client-side key-press event of
the extended TextBox control. The key-press event is wired up to this new delegate
function, which I ve also added to the JavaScript file:
_onKeyPressDelegate: function ()
{
var keyCode =
window.event.keyCode;
if (keyCode != 46
&& keyCode != 92 &&
(keyCode > 57 ||
keyCode < 48))
window.event.returnValue = false;
}
This function simply checks which key was pressed and
cancels the event if the associated character is non-numeric and is not the
decimal character (.) or the backspace key.
Finally to keep things tidy the event is unwired in
the destructor (under the Add custom dispose actions here comment of Figure
3) using this single line of JavaScript code:
$clearHandlers(this.get_element());
With these three changes, the initial boilerplate code of
Figure 3 now looks like the listing in Figure 4. The numeric textbox extender
is now complete and can be compiled successfully.
/// <reference name="MicrosoftAjax.js"/>
Type.registerNamespace("NumTextExt");
NumTextExt.ClientBehavior1 = function(element)
{
NumTextExt.ClientBehavior1.initializeBase(this,
[element]);
}
NumTextExt.ClientBehavior1.prototype = {
initialize: function() {
NumTextExt.ClientBehavior1.callBaseMethod(this,
'initialize');
// Add custom
initialization here
var e =
this.get_element();
this._keyPressDelegate =
Function.createDelegate(this,this._onKeyPressDelegate);
$addHandler(e,"keypress",this._keyPressDelegate);
},
_onKeyPressDelegate:
function () //Custom function
{
var keyCode =
window.event.keyCode;
if (keyCode != 46
&& keyCode != 92 &&
(keyCode > 57 || keyCode < 48))
window.event.returnValue = false;
},
dispose: function()
{
//Add custom dispose
actions here
$clearHandlers(this.get_element());
NumTextExt.ClientBehavior1.callBaseMethod(this,
'dispose');
}
}
NumTextExt.ClientBehavior1.registerClass
('NumTextExt.ClientBehavior1', Sys.UI.Behavior);
if (typeof(Sys) !== 'undefined')
Sys.Application.notifyScriptLoaded();
Figure 4: The
boilerplate JavaScript code of Figure 3 has been modified as shown here to
restrict keyboard input to numeric characters only.
Testing the Extender
To try out the extender, add a new Web application to your
solution. Then drag a ScriptManager control onto the page (as is required by
any page that takes advantage of Microsoft s client-side AJAX
framework).
Next, drag a standard TextBox control onto the Web form s
designer surface. A smart tag should appear, prompting you to optionally add an
extender. Click on it to add an extender. The dialog box in Figure 5 then
appears. Select the NumTextExt extender we created. This will have the effect
of linking the extender to the textbox by assigning TextBox1 to the control
extender s standard TargetControlID property.
Figure 5: Visual Studio 2008
provides enhanced support for control extenders with the new extender smart tag
and dialog box shown here.
Now set the Web application to be the solution s startup
project (via the right-click menu of Solution Explorer) and run the solution. If
prompted to add debugging to the web.config file, accept. The resulting browser
window should render a textbox that allows only decimal numbers to be entered. Other
characters are filtered out by the client-side JavaScript code defined by the
control extender.
Conclusion
One of the most notable changes in Web development since
the release of ASP.NET version 2.0 has been the emergence of AJAX.
So it only makes sense that one of the most notable new enhancements to ASP.NET
control creation is the addition of AJAX-related capabilities. In Visual Studio
2008 and ASP.NET 3.5, these enhancements have taken the form of the new ASP.NET
AJAX Server Control and ASP.NET AJAX Server Control Extender project templates,
which in turn take advantage of the new ScriptControl and ExtenderControl classes.
Every Web control developer needs to know about these
exciting new features. With such power at your fingertips you can create new cutting-edge
controls that exhibit all the user-friendly AJAX
features that modern users have come to expect.
The code samples in
this article were created using Beta 2 of Visual Studio 2008, so there is a
small chance that minor code changes may regrettably be necessary in order to
work with the final release version.
Steve C. Orr is an
ASPInsider, MCSD, Certified ScrumMaster, Microsoft MVP in ASP.NET, and author
of the book Beginning ASP.NET 2.0 AJAX by Wrox. He s
been developing software solutions for leading companies in the Seattle
area for more than a decade. When he s not busy designing software systems or
writing about them, he can often be found loitering at local user groups and
habitually lurking in the ASP.NET newsgroup. Find out more about him at http://SteveOrr.net or e-mail him at mailto:Steve@Orr.net.