In the preceding chapter, we covered the architecture of the AJAX Control Toolkit, describing at a high level what it has to offer and the attributes, classes, and interfaces that make it all happen.
The enhanced functionality you get in the toolkit, from attribute-based programming to rich animations, provides a compelling alternative to coding against the ASP.NET 2.0 AJAX Extensions and the Microsoft AJAX Library directly. In this chapter, we delve into the details of the toolkit a little further as we develop as series of extender controls that demonstrate the rich features the toolkit provides.
Adding Client-Side Behavior Using the ExtenderControlBase
The ASP.NET AJAX Control Toolkit provides many features to assist in the development of extender controls, such as the automatic creation of $createstatements, the use of attributes to decorate extender control properties that should be included in the $create statement creation, built-in designer support, and many more. In this section, we revisit the Image Rotator extender we created in Chapter 5, “Adding Client Capabilities to Server Controls,” and re-create it using the ASP.NET AJAX Control Toolkit. This approach enables us to compare the alternatives as we build the new extender.
The process of building an extender control using the ASP.NET AJAX Control Toolkit consists of four main steps.
- Create the template classes.
- Provide implementation for the inherited extender control class.
- Provide implementation for the Sys.UI.BehaviorBase-based JavaScript class.
- Attach the extender control to an existing server control.
Visual Studio 2008 Extender Control Library Template
The ASP.NET AJAX Control Toolkit comes with full support for Visual Studio 2008 in the form of a project template that is geared toward creating an extender control library project. The template, shown in Figure 11.1, creates a library project structure (see Figure 11.2) that contains an extender control class, a designer class, and a JavaScript behavior class. In this section, we look at the ImageRotatorExtender.cs, ImageRotatorDesigner.cs, and ImageRotatorBehavior.js files that the template generated for us as we begin to discuss creating a new and improved ImageRotator extender.
NOTE: Additional Template
The toolkit also comes with a template that generates the same files that can be used when you need to add additional extenders to an existing project, which can be found when you select Add New Item from a project.
The ImageRotatorExtenderclass shown in Listing 11.1 serves as the basis for our ImageRotator extender control. The class inherits from Extender ControlBase and provides a template that contains most of the required entries for us, such as the web resource registration of our associated behavior class, class attributes that associate the designer for the extender, the client script to be downloaded, and the target type for the extender. The template also creates a default property, demonstrating the use of the ExtenderControlProperty and DefaultValue attributes and the use of the GetPropertyValue method inside the property setter and getter.
NOTE: GetPropertyValue Method Version
The version of the GetPropertyValue method used by the template is an outdated one. When building out the class, we will change the implementation to use the GetPropertyValue<T> version instead.
The ImageRotatorDesigner class shown in Listing 11.2 will be the designer class for our ImageRotator extender control. The designer class provides default designer functionality for our extender control during design time. We associate the designer with our ImageRotatorExtender class by using the Designer attribute, which is automatically added when we use the template. The ExtenderControlBaseDesigner<T> class that the ImageRotatorDesigner class inherits from makes it possible for the properties of our extender control to show up in the Properties window while the design-time focus is on the image control we are extending. This default behavior provides a more efficient way of working with extenders and the controls they are extending.
The ImageRotatorBehaviorclass shown in Listing 11.3 will be the client-side behavior class for our ImageRotator extender control. The class consists of the same structure we used in Chapter 5, but now inherits from the AjaxControlToolkit.BehaviorBaseclass, which provides added functionality for working with client state and interacting with the asynchronous request events of the Sys.WebForms.PageRequestManager.
Inheriting from the ExtenderControlBase Class
The ASP.NET AJAX Control Toolkit comes with its own version of the System.Web.UI.ExtenderControl class, which provides additional functionality that supports the development pattern the toolkit is designed to work with. The AjaxControlToolkit.ExtenderControlBaseclass provides the inheritor support for serialization of property values, support for working with the toolkit-based attributes, seamless integration with control-based view state, support for working with client state, and the ability to specify an alternate script path for debugging and working with themes. The ImageRotatorExtender class in Listing 11.4 shows a much different-looking class than we saw in Chapter 5. The class no longer requires overrides for the GetScriptDescriptors and GetScriptReferences methods, it has class-level attributes, it has property-level attributes, and the property setters and getters are referencing their values through a method. So, let’s go over these changes and see how we develop an extender control building on the structure the template provided for us.
The setting of the assembly-based WebResourceattribute in our extender class is a pattern that all the extenders and script controls in the toolkit follow. This pattern helps centralize all the pieces for the component in one location instead of having to add an entry to the assembly when a new control is added to the toolkit. The attributes applied to the class that we cover in this section are the Designer, ClientScriptResource, RequiredScript, and TargetControlType attributes. The Designer attribute is used to specify the class that will provide design-time services to our extender. The ClientScriptResourceattribute is used to include the client-side scripts for our extender and consists of the resource type and the full resource name and should refer to an embedded resource. The RequiredScriptResource attribute brings in the timer script file that is associated with the Timer Script class that we will use in our behavior class. Finally, the Target ControlTypeattribute is used to limit the types of controls our extender can be associated with.
The RotationInterval and ImageList properties of our class have also changed with the use of attributes and the reliance on the GetProperty Value<T> and SetPropertyValue<T> methods to access our property data. The ExtenderControlProperty attribute is used to indicate that the property should be added to the ScriptComponentDescriptoras a property and later included in the $create statement that creates the behavior class on the client. The ClientPropertyName attribute is used to change the name of the property that is used when the property is added to the Script ComponentDescriptor from the default value of the property name to the name provided to the attribute. The DefaultValue attribute, which comes from the System.CompnentModel namespace, is used to indicate to designers and code generators the default value of the property. The Extender ControlBase class provides the GetPropertyValue<T> and GetProperty Value<T>generic methods that get and set the property value directly from the control view state. By using these methods in our property setters and getters, a consumer of our extender can work with it in the designer, declaratively in the HTML editor, or in code and be assured that during a post-back the values will be available.
Creating the AjaxControlToolkit.BehaviorBase Class
The ASP.NET AJAX Control Toolkit comes with its own version of the Sys.UI.Behavior class, which provides additional functionality and supports the development pattern the toolkit is designed to work with. The AjaxControlToolkit.BehaviorBase class provides inheritor support for working with client state and interacting with the asynchronous request events of the Sys.WebForms.PageRequestManager. The support for working with client state is provided by the get_ClientStateand set_ClientState methods that can be used to work with the string-based hidden field associated with your extender. The class also provides two methods tied to the beginRequest and endRequest events of the PageRequestManager, which can be overridden to provide specific functionality in your behavior in situations where an UpdatePanel is being used.
The ImageRotatorBehaviorclass shown in The ASP.NET AJAX Control Toolkit comes with its own version of the Sys.UI.Behavior class, which provides additional functionality and supports the development pattern the toolkit is designed to work with. The AjaxControlToolkit.BehaviorBase class provides inheritor support for working with client state and interacting with the asynchronous request events of the Sys.WebForms.PageRequestManager. The support for working with client state is provided by the get_ClientStateand set_ClientState methods that can be used to work with the string-based hidden field associated with your extender. The class also provides two methods tied to the beginRequest and endRequest events of the PageRequestManager, which can be overridden to provide specific functionality in your behavior in situations where an UpdatePanel is being used.
The ImageRotatorBehaviorclass shown in Listing 11.5 inherits from the BehaviorBase class and provides the client-side behavior for our extender control. The structure of this class is exactly the same as in Chapter 5, with the rotationIntervalproperty used to set the interval at which the images will be swapped out and the imageListproperty containing an array of the images. The one change to the class is in the use of the Sys.Timer class, which is part of the ASP.NET AJAX Control Toolkit. This class, which is contained in the Compat/Timer folder, wraps the window.setIntervalcall, providing a cleaner interface for this timer-specific functionality. The Sys.Timer class is just one of many that come with the toolkit that provide added functionality to the existing Microsoft AJAX Library. If you look in the Compat and Common folders in the toolkit library project, you will find classes for working with dates, drag and drop, and threading, just to name a few. inherits from the BehaviorBase class and provides the client-side behavior for our extender control. The structure of this class is exactly the same as in Chapter 5, with the rotationIntervalproperty used to set the interval at which the images will be swapped out and the imageListproperty containing an array of the images. The one change to the class is in the use of the Sys.Timer class, which is part of the ASP.NET AJAX Control Toolkit. This class, which is contained in the Compat/Timer folder, wraps the window.setIntervalcall, providing a cleaner interface for this timer-specific functionality. The Sys.Timer class is just one of many that come with the toolkit that provide added functionality to the existing Microsoft AJAX Library. If you look in the Compat and Common folders in the toolkit library project, you will find classes for working with dates, drag and drop, and threading, just to name a few.
Attaching the Extender to a Control
You can attach the ImageRotatorextender to an image control by using the new Extender Control Wizard (see Figure 11.3) that comes with Visual Studio 2008 and thus provide the same design-time experience we saw in Chapter 5. The wizard is available from the smart tag of the image control by selecting the Add Extender option, which opens the wizard. The wizard enables the user to select an extender control from a list and associate it with a control. In our case, we would select the ImageRotator extender to associate it with the image control. After we do that, we add values to the RotationInterval property and ImageList property using the Properties window of the image control.
Final Thoughts
If we compare our experience of creating extender controls using the ASP.NET AJAX Control Toolkit to using the classes provided by the ASP.NET 2.0 AJAX Extensions, we can see that our development experience is much simpler. The use of attributes to register our properties to be included in the $createstatements and to register our associated script files dramatically reduces the complexity of our code compared to implementing logic in the GetScriptDescriptors and GetScriptReferencesmethods. This convenience alone makes it worth using the toolkit, but if we tack on the added design-time features, support for working with client state, and the numerous added JavaScript files such as the Sys.Timer class, the reasons to switch get greater. The use of the toolkit can be compared to the use of the ActiveX Template Library (ATL) that was used to create ActiveX controls in C++. The template provided a ton of base classes and Visual Studio templates that made creating them a lot easier.
Adding Design-Time Support to Your Extender Control
The introduction of the Extender Wizard in Visual Studio 2008 has enhanced the design-time experience with regard to working with extender controls, and this section explains how to add design-time features of your own to give your controls that professional feel that users have become accustomed to.
Default Design-Time Experience
ImageRotatorDesignerclass shown in Listing 11.2 provides everything we need to get a basic design-time experience for our extender control. The ExenderControlBaseDesigner<T>that it inherits from makes it possible for the properties of our extender control to show up in the Properties window while the design-time focus is on the image control we are extending. Figure 11.4 shows the RotationIntervaland ImageListproperties that appear in the Properties window while the image control has focus in the designer. This default feature addresses one issue, which is being able to work with the ImageRotatorproperties in an integrated way, but still does not address the issue of data entry for the properties themselves and how that experience can be enhanced.
Adding Designers and Editors to Properties
In this section, we look at how to extend the design-time behavior of our ImageRotator ImageList property. The ImageList property that we worked with in Chapter 5 was rudimentary and prone to errors as a user entered in the values. In this version of the extender, we want to extend the functionality to support design-time editing and HTML source editing.
The road to these modifications requires a few steps as we add the functionality:
- Add attributes to the class.
- Add attributes to the property.
- Add editors to assist in assigning values.
- Create a type converter to support serialization.
Add Attributes to the Class
Most users expect when adding multiple entries to a control to be able to add them in the body of the HTML element. This is the experience we have when adding web service references or script references to the Script Manager and one we want to have in our control.
The ParseChildren attribute enables us to add multiple entries inside our ImageRotator HTML tag and treat those entries as a single property assignment. By setting the ChildrenAsPropertiesproperty to trueand the DefaultProperty to ImageList, as in Listing 11.6, we are effectively telling the designer that we want to have all the items contained in the body of our ImageRotator tag parsed and assigned to the ImageList property. The HTML fragment in Listing 11.7 shows what this looks like when the HTML editor is opened and the ImageRotator tag has entries.
NOTE: ASP.NET Server Control Designer References
The addition of designer features to your extenders requires some knowledge of how designers work. MSDN has some great information about this at http://msdn2.microsoft.com/en-us/ library/aa719973%28VS.71%29.aspx that covers adding design-time support to ASP.NET server controls.
Add Attributes to the Property
To fully implement the ability to add nested image entries to our Image Rotator extender, we need to add a couple of attributes, as shown in Listing 11.8, to our ImageListproperty, which provides hooks for the designer to integrate with our property and properly assign the image values.
The DesignerSerializationVisibility attribute is added to the property to ensure that the designer will serialize the contents of the property during design time. The setting of DesignerSerializationVisibility. Content instructs the designer to generate code for the contents of the tag and not the tag itself.
The PersistenceMode attribute is the other piece to this puzzle and is responsible for adding the <ImageUrl .. />entries inside our ImageRotator tag as we add values to the property in the Properties window. The setting of PersistenceMode.InnerProperty specifies that the property is persisted as a nested tag inside the ImageRotator, as shown in Listing 11.7.
Add Editors to Assist in Assigning Values
The use of editors in your extenders can greatly enhance the user experience during design time and in some cases can lead to more accurate entry of data. Recall from Chapter 5 that we entered images to the ImageList property by adding URL entries and separating them using commas. This rudimentary approach would not be expected by a consumer of a professional control. In this version of the ImageRotator, we want to enhance the data entry of the images by providing an editor that can be used to add image URL entries and have those entries placed into the body of our ImageRotator HTML tag. If we go back to the ScriptManager control, this is the experience it provides when adding web service or script references while in the Properties window.
The ImageList property in this version of the ImageRotator uses two editors to provide a rich design-time experience when adding ImageUrl entries. The first editor is a Collection editor, shown in Figure 11.5, and is designed to assist in adding, editing, and removing values that are based on a Collection. The editor is automatically associated with our ImageList property because the type of the property is a Collection. The second editor we will use is the ImageUrlEditor, shown in Figure 11.6, which the ImageUrlentry uses to assist the user in entering a URL. This editor is associated with the Urlproperty of the ImageUrlclass, as shown in Listing 11.9, by adding the Editor attribute to the property. We use the Editor attribute to configure which editor to use when adding values to the property in the designer. In our case, we are using the ImageUrlEditor to provide the user with a clean way to find an image located in a web application and assign the value to the ImageUrl property. The use of the associated UrlProperty attribute provides a filter that identifies specific file types that can be used to filter against the ImageUrl property.
Create a Type Converter to Support Serialization
The use of complex types presents a few challenges in the ASP.NET AJAX Control Toolkit during the script generation process. The problem arises in how the ASP.NET AJAX Control Toolkit serializes your extender control properties as it creates the $create statement. By default, the toolkit tries to get the default string representation of the value your property represents. In most cases, this is an easy task because most simple types convert to a string relatively easily. If you are using complex types, however, this can present a problem because the default ConvertToString() representation of a complex object is its type name. To resolve this issue, you must create a type converter and associate it with the complex type. When the ASP.NET AJAX Control Toolkit encounters a type during script generation, it looks to see whether the type has a converter. If it does, it uses the converter to convert the data instead of using the default ConvertToString() method. In this section, we walk through creating a System.Component Model.TypeConverter that will be used to convert our ImageUrlList type into a JavaScript Object Notation (JSON) string that can be consumed on the client.
The ImageListConverter, shown in Listing 11.10, is designed to convert the ImageList to a JSON array of image URLs that are then passed back to the client. The creation of this type converter now enables us to return a data format that the client can use instead of a string that contains the type name of the ImageList. For the type converter to be used, we need to associate it with the ImageList type. We do this by adding the TypeConverter attribute to the ImageListclass, as shown in Listing 11.11, and assigning the type of the ImageList to it. Now when the toolkit performs a Convert ToString on the ImageList, the JSON string representation of the Image List will be returned.
NOTE: Use of the DataContractJsonSerializer
In more complex situations, you might use the DataContract JsonSerializer that we discussed in Chapter 8, “ASP.NET AJAX Communication Architecture,” which replaces theSystem.Web.UI. JavaScriptSerializer class as the new JSON serializer to convert your data to JSON format.
Adding Animations to Your Extender Control
The ASP.NET AJAX Control Toolkit comes with a rich animation framework that provides support for creating cool visual effects on your pages. The animation framework consists of a set of JavaScript and .NET classes that enable you to build up animations of all types, including animations that run sequentially or in parallel, animations that fade the opacity of a control in and out, and animations that transition from one color to the next. The framework provides support for building these animations using the JavaScript API directly or using a declarative approach that consists of adding markup in the HTML editor. The following sections examine how to add animation functionality to extender controls.
Animations Using the JavaScript API
The ImageRotator extender we created earlier provided little in the area of effects as the images switched and resulted in very fast transition from one image to the next, which wouldn’t catch a viewer’s attention. In this section, we create a new version of the ImageRotator, called the Animated ImageRotator, that fades in the image as it switches from one image to the next and provides this feature in addition to the existing functionality of the ImageRotator. As we cover how to add this new animation functionality, we gloss over the topics we have already covered, focusing only on implementing the animation pieces.
To add this functionality to the AnimatedImageRotator, we need to register the animation scripts with the AnimatedImageRotatorExtender class and add logic to the behavior class to call the animation when the image changes.
Registering the Animation Scripts
To register the script files so that they are downloaded to the browser, we need to add the RequiredScript attribute to the AnimatedImageRotator Extender class, as shown in Listing 11.12. We use the RequiredScript attribute in this case to ensure that the animation.js, timer.js, and common.js script files associated with the AnimationScripts type are included with the scripts brought down to the browser for our control. This style of adding scripts associated with a type is a common practice in the toolkit and is clean way to include dependent scripts associated with a type.
Calling Animation APIs
The ASP.NET AJAX Control Toolkit contains a JavaScript API that you can use to provide animation support on the client. In the case of our Animated ImageRotatorextender, we will use the FadeAnimation, which is part of the animation API, to provide a fade-in effect when the images on our image control change. The JavaScript code to implement this functionality will be contained in our behavior class and will integrate with the existing features of the ImageRotator.
The AnimatedImageRotatorbehavior class, shown in Listing 11.13, takes the ImageRotator behavior and adds a fade animation when the image changes, to fade the image into view. The constructor of the FadeAnimation takes the target of the animation, the duration of the animation, the number of steps per second, the effect, the minimum opacity, the maximum opacity, and whether to adjust for layout in Internet Explorer. In our case, the BannerImage image control will be the target of our animation, and the duration of our animation will be hard coded to 20% of the time the image is visible. To provide a clean animation, we will set the animation steps to 150, and combine that with a fade-in effect that will cause the image to transition in when the image changes. During this transition, we will start off with an opacity of 0, which will give us a full view of the image background, and then through the 150 steps work our way to a full view of the image with an opacity of 1. Table 11.1 lists some of the FadeAnimationproperties and provides a little more information about what they do.
After we associate the animation to the element, starting, stopping, and pausing the animation is just a method call away, making it simple to manipulate the animation. In the AnimatedImageRotator, the load event of the image is used to trigger the animation to play because it will be fired each time our Sys.Timer calls the _rotateImage method. To do this, we associated the _onLoadImage event handler with the onLoad event of the image and called the play method on the animation inside the function. Now each time the load event occurs, the animation plays, transitioning the image into view. One of the side effects of working with an animation in a situation like this is a potential race condition if the duration was set too long. When working with transition-type animations like the FadAnimation, pay close attention to how you are using it to ensure the animation will work in all cases.
Animations Using the Declarative Method
The declarative approach to animation in the toolkit provides a nice extensibility path for consumers of your extender. In our previous example, we hard coded all the animation functionality inside our extender, providing little support for developer customization. In some cases, this might be all that is needed. In other cases, however, you might need to provide a more robust solution that provides a JavaScript-free way to customize animations. In this section, we replicate the same functionality we created in the preceding section, but we provide a more extensible approach consumers of our extender can use when they are configuring it in the designer. The extender we create has just one feature: the capability to run a FadeIn animation when the onLoad event of an associated image control occurs. This new extender will be used in addition to the ImageRotatorextender we created earlier, which had no animation functionality. This refined approach to adding animation support builds on the principle that many extenders can be placed on a single control to provide combined client-side capabilities. To get started, let’s take a look at what the declarative syntax or our control will look like before we go into the implementation details. Just as in the preceding section, as we cover how to add this new animation functionality we gloss over the topics we have already covered, focusing only on implementing the declarative animation pieces.
Overview of Declarative Syntax
To get started, let’s look at the HTML source we will be working toward being able to work with in our ImageAnimationextender. The source in Listing 11.14 contains an ImageAnimationExtendertag that contains in its body an Animationstag. As you might guess, the approach here is to add various animations that are driven by events raised by the image control we are extending. In our case, we are working with the OnLoad event and adding a Sequenceanimation that will call a child Fadeanimation. A Sequenceanimation is designed to run all its child animations one at a time until all have finished. So, what this source tells us is that our extender will have an animation that will be tied to the OnLoad event of the image control and will run the child Fade animation whenever the OnLoad event occurs.
Providing Declarative Support in Your Extender Class
The AnimationExtenderControlBase class provides most of the functionality we need to parse the Animationtag and all its contents. This class provides internal methods that convert the XML representation of the animation into JSON format, which our behavior will then use to run the animation, and also provides the Animation property that we see in Listing 11.15. The following sections cover the steps needed to ensure the extender will work correctly.
- Add attributes to the class.
- Create a property for the event.
- Add attributes to the property.
Add Attributes to the Class
This type of extender has a couple of added class attribute entries of interest to us. The first is the inclusion of the RequiredScript attribute for the AnimationExtender type. The AnimationExtender class provides a lot of the client-side functionality we will be using in our extender control, and by using this type in our RequiredScripts attribute, we are guaranteed that the scripts will be present on the client for us to use. The second attribute is the System.Web.UI.Design.ToolboxItem attribute, which enables our control to show up in the toolbox of Visual Studio. It might seem strange that we have to add this because all our other extenders didn’t. If we look at the attributes on the AnimationExtenderControlBaseclass, however, the support for viewing in the toolbox has been turned off. Therefore, we must reset this value on our control so that it will show up in the toolbox.
Create a Property for the Event
The pattern when creating extenders of this type is to add a property for each event you want to interact with. In our case, we are working with the OnLoad event, so we create a property named OnLoad (to make it easy to understand what the event is). If we were to choose other events, we would name them based on the DOM event they represent. The property accessor for these events must use the GetAnimation and SetAnimation methods to ensure proper data conversion into JSON as the data is stored and retrieved out of the extender’s view state.
Add Attributes to the Event Property
The event property must have the Browsable, DefaultValue, Extender ControlProperty, and DesignerSerializationVisibility attributes applied to it. The Browsableattribute stops the property from showing up in the Properties window and therefore excludes the property from being assigned in the Properties window. This is needed because no editor is associated with this property, and we don’t want users to try to add anything into the Properties window that would corrupt the values. The Designer SerializationVisibilityattribute with a value of DesignerSerialization Visibility.Hiddenis used to indicate that the property value should not be persisted by the designer because the Animation property will take care of that for us. The DefaultValue attribute indicates to the designer that the default value will be null, and the ExtenderControlProperty attribute is used to register the property with the ScriptComponentDescriptor.
Adding Declarative Support to Your Behavior Class
The ImageAnimationBehavior class, shown Listing 11.16, provides all the client-side functionality for our extender with support from the animation script files associated with the AutomationExtenderclass. These associated scripts provide support for converting the JSON representation of the FadeIn animation that was captured on the server to an actual animation, support for associating the animation with the high-level OnLoadevent, and support for playing the animation when the OnLoad event occurs.
You need to complete a few steps for each event you plan to work with:
- Add variables to the class.
- Create functions.
- Add handlers.
Add Variables to the Class
Each event that your behavior will work with needs a variable that references the GenericAnimationBehaviorfor the event and a delegate that will be called for the event that will be processed. In the ImageAnimation Behavior class, we use the _onLoad variable to store a reference to the GenericAnimationBehaviorclass and the _onLoadHandlervariable to store a reference to the delegate that will handle the onLoadevent. The guidelines established so far in the toolkit use a naming convention that includes the event name in all the variable names.
Create Functions
The behavior needs a series of functions for each event you will work with. The get_OnLoadand set_OnLoadfunctions in our case take care of working with the JSON-based data for the FadeIn animation and utilize the functionality provided by the GenericAnimationBehavior class to store and retrieve that data. The get_OnLoadBehavior function returns a reference to the GenericAnimationBehavior instance that was created for our FadeIn animation, providing the ability to work with the behavior that directly exposes the play, stop, and quit methods common to all animations.
Add Handlers
Handlers must be added for each event the behavior will process and should correspond to the events exposed on the extender control. In our case, we are working with the onLoad event, so we need to create the _onLoadHandler delegate and associate it with the onLoad event of the image using the $addHandlershortcut. The opposite of this must happen in the dispose of our behavior, when we use the $removeHandler shortcut to ensure proper memory cleanup.
Final Thoughts
The HTML source for our sample, shown Listing 11.14, contains a Fadeanimation that targets the BannerImage control and runs for a duration of .3 seconds. We could have chosen almost any type of animation as long as it occurred when the OnLoadevent fired on the BannerImageimage control. This flexibility provides a JavaScript-free way to set up animations of any type when a pattern such as this is used. In fact, this is exactly how the Animation extender works; and if it weren’t for the way it handles the OnLoad event, we would have used it in our example.
SUMMARY
The AJAX Control Toolkit comes with quite a bit of functionality that you can use to create truly interactive extenders that require much less coding than if you were to use the ASP.NET 2.0 AJAX Extensions directly. As you learned in this chapter, the toolkit provides a much richer environment for creating extender controls than using the ASP.NET 2.0 AJAX Extensions alone. In addition, the toolkit includes myriad controls you can either use or build on, making the toolkit a compelling alternative.