Create Control Extenders

Using Visual Studio 2008, ASP.NET 3.5, and AJAX

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.

 

_

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

               GetScriptDescriptors(Control targetControl)

       {

           ScriptBehaviorDescriptor descriptor = new

             ScriptBehaviorDescriptor(

               "NumTextExt.ClientBehavior1",

               targetControl.ClientID);

           yield return descriptor;

       }

       // Generate the script reference

       protected override IEnumerable

               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.

 

///

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.

 

///

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:[email protected].

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish