11.2. Building a Server-Side ASP.NET AJAX Control

Creating custom ASP.NET AJAX client-side controls is a fairly intensive exercise in JavaScript. Calling control methods, handling events, and even instantiating the control itself requires JavaScript code to be written. While some ASP.NET developers understand how to write JavaScript code, others may not have a complete understanding of the language and may prefer to work with server-side objects that can be manipulated using VB.NET or C#. They may prefer to be shielded from JavaScript code whenever possible.

Because server-side controls can output both HTML and JavaScript, they're good candidates for use with ASP.NET AJAX client-side controls. Developers familiar with defining and interacting with server-side controls can use an AJAX-enabled server-side control without having to worry about the client-side complexities. A nice "feature" of ASP.NET AJAX server-side controls is that once you have created the client-side script that handles all of the HTML output and event handling (as with the AlbumViewer control shown in this chapter), going a little further to create a server-side control is fairly straightforward and requires very little VB.NET or C# code. After all, most of the control's functionality is performed by the client-side script.

There are a few different paths to creating an ASP.NET AJAX server control. To choose the correct path, you need to decide what type of control you want to create. Will the control be visual, or is it something that runs in the background like a timer? Will the control extend functionality of another control? The answer to these questions determines how the server-side control is built. For example, if you want to extend an existing control's functionality by adding AJAX capabilities to it, you'll want to derive from the System.Web.UI.ExtenderControl class. If you're writing a visual control from scratch that generates HTML and JavaScript, you'll want to derive from System.Web.UI.ScriptControl derives from System.Web.UI.WebControl.

The AlbumViewer server-control, discussed next, derives from ScriptControl and leverages the AlbumViewer client-side control script discussed earlier in this chapter. It lives in an ASP.NET control library project within Visual Studio 2008. Before getting into specifics about the server-side control, let's examine how to embed a client-side control script into a server-side control assembly.

11.2.1. Embedding Scripts in Server-Side Controls

ASP.NET AJAX server-side controls perform two main functions. First, they output a client-side control script to the browser that handles the bulk of the functionality required by the control. This includes interaction with the end user, event handling, data binding, calls to remote data source, and more. Second, they define properties that can be set on the server-side and passed to the client-side script.

his allows ASP.NET developers to define properties using standard ASP.NET control syntax without worrying about writing custom JavaScript code or even using the ASP.NET AJAX script library's $create method to instantiate the control.

Client-side ASP.NET AJAX control scripts can be embedded directly in ASP.NET server control assemblies by marking the scripts as an embedded resource. First, add a script file to an ASP.NET server control project (officially called a Class Library project in Visual Studio 2008) and add all of the client-side functionality to it. Next, right-click the created script file in the Visual Studio 2008 Solution Explorer, select Properties and set the Build Action property to a value of Embedded Resource. This causes the compiler to embed the script file directly in the control's assembly. Figure 11-2 shows the Properties window for the embedded script file.

To make the script accessible, add the following assembly attribute immediately above the server control's namespace definition in code file (C# is shown here):

[assembly: System.Web.UI.WebResource("AlbumViewer.AlbumViewer.js",
  "text/javascript")]

Figure 11-2. Figure 11-2

This makes the script accessible through an HttpHandler built into ASP.NET AJAX called ScriptResource.axd and avoids the need to deploy the physical script file along with the server control assembly, which can greatly simplify deployment and maintenance. The WebResource attribute's constructor accepts the name of the resource followed by the content-type of the resource. The name given to the resource is the assembly name followed by the name of the script (AlbumViewer.AlbumViewer.js, in this case). Although JavaScript is used in this example, images can also be embedded in custom server controls using the same technique. One disadvantage of embedding scripts or images into assemblies is that they can't be modified on the Web server; you would have to rebuild the assembly with the modified objects and redeploy it to the Web server.

11.2.2. Creating a Control Class

The AlbumViewer ASP.NET AJAX server-side control allows a developer to set properties on the control using familiar ASP.NET server control syntax. After property values are set, the control handles outputting the client-side control script that's embedded as a resource and creates a new instance of the control using the $create method. Property values set on the server side are passed to the $create method through a JSON object that is passed as a parameter to $create.

Because the AlbumViewer server-side control doesn't extend an existing control it derives from System.Web.UI.ScriptControl. Had the control extended an existing control, such as a TextBox, it would inherit from System.Web.UI.ExtenderControl located in the System.Web.Extensions.dll assembly that's installed with the ASP.NET AJAX framework. The ScriptControl class contains two key methods, shown in the following table.

MethodDescription
GetScriptDescriptorsGets a collection of script descriptors that represent JavaScript components on the client. This method is used to map server-side control properties to client-side control properties.
GetScriptReferencesGets a collection of ScriptReference objects that define script resources required by the control. This method is used to identify one or more embedded script resources in a control assembly and output them to the client.

Listing 11-13 shows the shell for the AlbumViewer server-side control. Notice that it derives from ScriptControl.

Example 11-13. Creating an AlbumView server-side control
using System;
using System.Configuration;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

//Client-side script file embedded in assembly
[assembly: System.Web.UI.WebResource("AlbumViewer.AlbumViewer.js",
  "text/javascript")]
namespace Wrox.ASPAJAX.Samples
{
    public class AlbumViewer : ScriptControl
    {

        protected override IEnumerable<ScriptReference> GetScriptReferences()
        {
            return GetControlScriptReferences();
        }

        protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors()
        {
            return GetControlScriptDescriptors();
        }

    }
}

The two overridden methods shown in Listing 11-13 delegate processing to two custom methods included in the class named GetControlScriptReferences and GetControlScriptDescriptors. These two methods are shown in Listing 11-14.

Example 11-14. Mapping server-side properties to client-side properties and defining script references
protected virtual IEnumerable<ScriptDescriptor> GetControlScriptDescriptors()
{
    ScriptControlDescriptor descriptor =
      new ScriptControlDescriptor("Wrox.ASPAJAX.Samples.AlbumViewer",
      this.ClientID);
    descriptor.AddProperty("AlbumDivOverCssClass", this.AlbumDivOverCssClass);
    descriptor.AddProperty("AlbumDivOutCssClass", this.AlbumDivOutCssClass);
    descriptor.AddProperty("AlbumTitleCssClass", this.AlbumTitleCssClass);
    descriptor.AddProperty("AlbumArtistCssClass", this.AlbumArtistCssClass);
    descriptor.AddProperty("SongTitleCssClass", this.SongTitleCssClass);

descriptor.AddProperty("ServicePath", this.ServicePath);
    descriptor.AddProperty("ServiceMethod", this.ServiceMethod);
    descriptor.AddProperty("ShowSearchBox", this.ShowSearchBox);
    //could also use: yield return descriptor;

    return new ScriptDescriptor[] { descriptor };
}

protected virtual IEnumerable<ScriptReference> GetControlScriptReferences()
{
    ScriptReference r = new ScriptReference();
    r.Assembly = "AlbumViewer";
    r.Name = "AlbumViewer.AlbumViewer.js";
    //could also use:  yield return r;
    return new ScriptReference[] { r };
}

The GetControlScriptReferences method shown in Listing 11-14 creates a ScriptReference object and identifies the script resource that the server control needs to send to the client (AlbumViewer.AlbumViewer.js, in this case). The GetControlScriptDescriptors method creates a new ScriptControlDescriptor object that maps server-side control properties to client-side control properties. This is necessary so that the property values set on the control by a developer can be passed to the $create method used to instantiate the client-side control. The properties defined in the AlbumViewer server-side control are the same ones discussed earlier in the chapter for the client-side control (AlbumDivOverCssClass, AlbumDivOutCssClass, and so on).

Listing 11-15 shows the complete code for the AlbumViewer server-side control.

Example 11-15. The completed AlbumViewer control
using System;
using System.Configuration;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

//Client-side script file embedded in assembly
[assembly: System.Web.UI.WebResource("AlbumViewer.AlbumViewer.js",
  "text/javascript")]
namespace Wrox.ASPAJAX.Samples
{
    public class AlbumViewer : ScriptControl
    {
        string _AlbumDivOverCssClass;
        string _AlbumDivOutCssClass;
        string _AlbumTitleCssClass;

string _AlbumArtistCssClass;
        string _SongTitleCssClass;
        string _ServicePath;
        string _ServiceMethod;
        bool _ShowSearchBox;

        #region Properties

        public string AlbumDivOverCssClass

        {
            get { return _AlbumDivOverCssClass; }
            set { _AlbumDivOverCssClass = value; }
        }

        public string AlbumDivOutCssClass
        {
            get { return _AlbumDivOutCssClass; }
            set { _AlbumDivOutCssClass = value; }
        }

        public string AlbumTitleCssClass
        {
            get { return _AlbumTitleCssClass; }
            set { _AlbumTitleCssClass = value; }
        }

        public string AlbumArtistCssClass
        {
            get { return _AlbumArtistCssClass; }
            set { _AlbumArtistCssClass = value; }
        }

        public string SongTitleCssClass
        {
            get { return _SongTitleCssClass; }
            set { _SongTitleCssClass = value; }
        }

        public string ServicePath
        {
            get { return _ServicePath; }
            set { _ServicePath = value; }
        }

        public string ServiceMethod
        {
            get { return _ServiceMethod; }
            set { _ServiceMethod = value; }
        }

        public bool ShowSearchBox
        {

get { return _ShowSearchBox; }
            set { _ShowSearchBox = value; }
        }

        #endregion

        public AlbumViewer() {}

        protected virtual IEnumerable<ScriptDescriptor>
          GetControlScriptDescriptors()
        {
            ScriptControlDescriptor descriptor =
              new ScriptControlDescriptor("Wrox.ASPAJAX.Samples.AlbumViewer",
              this.ClientID);
            descriptor.AddProperty("AlbumDivOverCssClass",
              this.AlbumDivOverCssClass);
            descriptor.AddProperty("AlbumDivOutCssClass",
              this.AlbumDivOutCssClass);
            descriptor.AddProperty("AlbumTitleCssClass", this.AlbumTitleCssClass);
            descriptor.AddProperty("AlbumArtistCssClass",
              this.AlbumArtistCssClass);
            descriptor.AddProperty("SongTitleCssClass", this.SongTitleCssClass);
            descriptor.AddProperty("ServicePath", this.ServicePath);
            descriptor.AddProperty("ServiceMethod", this.ServiceMethod);
            descriptor.AddProperty("ShowSearchBox", this.ShowSearchBox);
            //could also use: yield return descriptor;
            return new ScriptDescriptor[] { descriptor };
        }

        protected virtual IEnumerable<ScriptReference> GetControlScriptReferences()
        {
            ScriptReference r = new ScriptReference();
            //Use following when client-side script isn't
            //embedded in custom control:
            //reference.Path = this.ResolveClientUrl("~/Scripts/AlbumViewer.js");
            r.Assembly = "AlbumViewer";
            r.Name = "AlbumViewer.AlbumViewer.js";
            //could also use:  yield return r;
            return new ScriptReference[] { r };

        }

        protected override IEnumerable<ScriptReference> GetScriptReferences()
        {
            return GetControlScriptReferences();
        }

        protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors()
        {
            return GetControlScriptDescriptors();
        }

    }
}

Now that you've seen the steps required to build a custom ASP.NET AJAX server control, let's examine how to use one in an ASP.NET page.

11.2.3. Using a Custom ASP.NET AJAX Control in an ASP.NET Page

Once the AlbumViewer server-side control project is compiled and the generated assembly is referenced by an ASP.NET Web site project, the control can be registered in an ASP.NET page by using the Register directive:

<%@ Register Assembly="AlbumViewer" Namespace="Wrox.ASPAJAX.Samples"
    TagPrefix="ajax" %>

This directive references the assembly name (AlbumViewer), the namespace that the control resides in (Wrox.ASPAJAX.Samples), as well as the tag prefix that should be used to define the control in the ASP.NET page (ajax). Once registered, this control can be used in the page just the same as any other ASP.NET server control. You simply need to define the tag prefix and class name followed by all of the necessary properties in the Register directive. An example of adding the AlbumViewer control into a page is shown here:

<ajax:AlbumViewer ID="divAlbums" runat="server" ShowSearchBox="true"
  AlbumDivOverCssClass="AlbumDivOver"
  AlbumDivOutCssClass="AlbumDivOut" AlbumTitleCssClass="AlbumTitle"
  AlbumArtistCssClass="AlbumArtist" SongTitleCssClass="SongTitle"
  ServicePath="AlbumService.asmx" ServiceMethod="GetAlbums" />

After the page is called by an end user through a browser, the necessary client-side script code used by the AlbumViewer control will automatically be added to the rendered output by the ScriptManager control. A portion of the output generated by ScriptManager that instantiates the AlbumViewer control is shown in Listing 11-16.

Example 11-16. $create client-side code output by the AlbumViewer control
<script type="text/javascript">
<! --
    Sys.Application.initialize();
    Sys.Application.add_init(function() {

        $create(Wrox.ASPAJAX.Samples.AlbumViewer,
          {"AlbumArtistCssClass":"AlbumArtist",
           "AlbumDivOutCssClass":"AlbumDivOut",
           "AlbumDivOverCssClass":"AlbumDivOver",
           "AlbumTitleCssClass":"AlbumTitle",
           "ServiceMethod":"GetAlbums",
           "ServicePath":"AlbumService.asmx",
           "ShowSearchBox":true,
           "SongTitleCssClass":"SongTitle"},
           null, null,
           $get("divAlbums"));
        });
//  -- >
</script>

The AlbumViewer.js script embedded in the control is automatically referenced through a script tag embedded into the page. The script tag's src attribute points to a ScriptResource.axd HttpHandler that will extract the script from the server-side assembly where it was embedded and send it down to the browser:

<script
  src="/Chapter11/ScriptResource.axd?d=eyWA0k6p8cJT5ZxERTSqjh74z_7LL-
       XVOadc8XgiZ-JKa85A2IV0dD9FkMF5UiS40&amp;t=633048513771318000"
  type="text/javascript">
</script>

11.2.4. Creating a Control Extender using the ASP.NET AJAX Control Toolkit

Functionality of existing ASP.NET controls such as TextBox and GridView can be extended by using the System.Web.UI.ExtenderControl class included in the System.Web.Extensions assembly or the AjaxToolkit.ExtenderControlBase class provided by the ASP.NET AJAX Control Toolkit's AjaxControlToolkit assembly (additional details on using the toolkit were provided in Chapter 7). Both classes allow existing controls to be extended with client-side behaviors. For example, a filter could be added to a TextBox control to only allow specific characters to be entered or a GridView control's header could be frozen so that it stays fixed as a user scrolls through rows.

Although both classes ultimately lead to the same end result, the ExtenderControlBase class and related classes available in the AJAX Control Toolkit can simplify the process of mapping server-side properties to client-side properties and minimize the amount of code you have to write to extend and existing control. This section outlines key steps you can follow to build a custom AJAX control using ASP.NET AJAX Control Toolkit classes.

11.2.4.1. Creating a Client-Side Extender Class

To get started building a custom extender control, you need to create a Class Library project in Visual Studio and place the AjaxControlToolkit.dll assembly in the project's bin folder (download the toolkit and related assembly from www.codeplex.com/AjaxControlToolkit). When the toolkit assembly is in the bin folder you can create the client-side functionality that will be applied to an existing control to extend it. To do this, add a JavaScript file into the project, right-click it in the Solution Explorer and select Properties from the menu. Change the file's Build Action property to a value of Embedded Resource.

Figure 11-3 shows an example of how a client-side extender control can be applied to a GridView control at runtime. The extender freezes the header row as users scroll through rows of data so that it remains at a fixed position. Listing 11-17 shows the code for the client-side extender class.

NOTE

The code in Listing 11-17 is provided for demonstration purposes and is designed to work with Firefox and Internet Explorer only. Additional testing and functionality may be needed if you plan to use it in a production environment or with other browsers.

Figure 11-3. Figure 11-3

Example 11-17. Defining the GridViewHeaderBehavior client-side class
Type.registerNamespace('Wrox.ASPAJAX.Samples'),

Wrox.ASPAJAX.Samples.GridViewHeaderBehavior = function(element) {
    /// <summary>
    /// The GridViewHeaderBehavior is used to fix a GridView control header and
    /// make the control scrollable
    /// </summary>
    /// <param name="element" type="Sys.UI.DomElement">
    /// The GridView element this behavior is associated with
    /// </param>
    Wrox.ASPAJAX.Samples.GridViewHeaderBehavior.initializeBase(this, [element]);
    this._WrapperDivCssClass = null;
}

Wrox.ASPAJAX.Samples.GridViewHeaderBehavior.prototype = {
    initialize : function() {
        /// <summary>
        /// Initialize the behavior
        /// </summary>
        Wrox.ASPAJAX.Samples.GridViewHeaderBehavior.callBaseMethod(this,
         'initialize'),
        var element = this.get_element();

this._FreezeGridViewHeader();
    },

    dispose : function() {
        /// <summary>
        /// Dispose the behavior
        /// </summary>
        var element = this.get_element();
        Wrox.ASPAJAX.Samples.GridViewHeaderBehavior.callBaseMethod(this,
         'dispose'),
    },

    _FreezeGridViewHeader : function () {
        var grid = this.get_element();
        if (grid != 'undefined')
        {
            grid.style.visibility = 'hidden';
            var div = null;
            if (grid.parentNode != 'undefined')
            {
                div = grid.parentNode;
                if (div.tagName == 'DIV')
                {
                    div.className = this._WrapperDivCssClass;
                    div.style.overflow = 'auto';
                }
            }
            var tags = grid.getElementsByTagName('TBODY'),
            if (tags != 'undefined')
            {
                var tbody = tags[0];
                var trs = tbody.getElementsByTagName('TR'),
                var headerHeight = 8;
                if (trs != 'undefined')
                {
                    headerHeight += trs[0].offsetHeight;
                    var headTR = tbody.removeChild(trs[0]);
                    var head = document.createElement('THEAD'),
                    head.appendChild(headTR);
                    grid.insertBefore(head, grid.firstChild);
                }
                tbody.style.height = (div.offsetHeight -  headerHeight) + 'px';
                tbody.style.overflowX = 'hidden';
                tbody.overflow = 'auto';
                tbody.overflowX = 'hidden';
            }
            grid.style.visibility = 'visible';
         }
    },

    get_WrapperDivCssClass : function() {
        return this._WrapperDivCssClass;

},

    set_WrapperDivCssClass : function(value) {
        this._WrapperDivCssClass = value;
        this.raisePropertyChanged('WrapperDivCssClass'),
    }
}

Wrox.ASPAJAX.Samples.GridViewHeaderBehavior.registerClass(
  'Wrox.ASPAJAX.Samples.GridViewHeaderBehavior', AjaxControlToolkit.BehaviorBase);

The code in Listing 11-17 follows the standard prototype design pattern discussed earlier and relies on the ASP.NET AJAX script library's Type class to register a namespace and derive the Wrox.ASPAJAX.Samples.GridViewHeaderBehavior custom client-side extender class from a base class named AjaxControlToolkit.BehaviorBase. As the namespace infers, BehaviorBase is provided by the ASP.NET AJAX Control Toolkit.

11.2.4.2. Creating a Server-Side Extender Class

Once you have a client-side extender class available to use, add a reference to the AjaxControlToolkit assembly located in the bin folder. Then add a new C# or VB.NET class into the project (the class discussed here is named GridViewHeaderExtender). The class must import the AjaxControlToolkit namespace and derive from ExtenderControlBase which is located in the AjaxControlToolkit namespace.

The GridViewHeaderExtender server-side extender control needs to automatically output the script shown earlier in Listing 11-17 to the client. This can be accomplished by using the WebResource attribute along with the Toolkit's ClientScriptResource attribute, as shown in Listing 11-18.

Example 11-18. Defining the GridViewHeaderDemo server-side class
using System;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Web.UI;
using System.ComponentModel;
using System.ComponentModel.Design;
using AjaxControlToolkit;

[assembly: WebResource("GridViewHeaderDemo.GridViewHeaderBehavior.js",
          "text/javascript")]

namespace GridViewHeaderDemo
{

    [TargetControlType(typeof(GridView))]
    [ClientScriptResource("Wrox.ASPAJAX.Samples.GridViewHeaderBehavior",
      "GridViewHeaderDemo.GridViewHeaderBehavior.js")]
    [ToolboxItem("System.Web.UI.Design.WebControlToolboxItem, System.Design,
       Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]

public class GridViewHeaderExtender : ExtenderControlBase
    {
        [DefaultValue("")]
        [Description("CSS class to apply to the GridView wrapper div element.
          Example of a wrapper div style: .WrapperDiv
          {width:800px;height:400px;border: 1px solid black;}")]
        [ExtenderControlProperty]
        [ClientPropertyName("WrapperDivCssClass")]
        public string WrapperDivCssClass
        {
            get { return GetPropertyValue<string>("WrapperDivCssClass",
              string.Empty); }
            set { SetPropertyValue<string>("WrapperDivCssClass", value); }
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            if (String.IsNullOrEmpty(this.WrapperDivCssClass))
            {
                throw new ApplicationException("WrapperDivCssClass property " +
                  "value must be defined for the GridViewHeaderExtender " +
                  "control. Here's an example of a wrapper div style that " +
                  "should be defined in the page and referenced with the" +
                  "WrapperDivCssClass property: .WrapperDiv " +
                  "{width:800px;height:400px;border: 1px solid black;}");
            }

            if (this.Enabled && !this.Page.Items.Contains("GridViewHeaderStyles"))
            {
                this.Page.Items["GridViewHeaderStyles"] = true;
                this.Page.Header.StyleSheet.CreateStyleRule(
                  new GridViewThCssClass(), null, "." +
                   this.WrapperDivCssClass + " TH");
                this.Page.Header.StyleSheet.CreateStyleRule(
                  new GridViewTrCssClass(), null, "." +
                   this.WrapperDivCssClass + " TR");
            }
        }

        private class GridViewTrCssClass : Style
        {
            protected override void FillStyleAttributes(
              CssStyleCollection attributes, IUrlResolutionService urlResolver)
            {
                base.FillStyleAttributes(attributes, urlResolver);
                attributes[HtmlTextWriterStyle.Height] = "0px";
            }
        }

        private class GridViewThCssClass : Style

{
            protected override void FillStyleAttributes(
              CssStyleCollection attributes, IUrlResolutionService urlResolver)
            {
                base.FillStyleAttributes(attributes, urlResolver);
                attributes[HtmlTextWriterStyle.Position] = "relative";
            }
        }
    }
}

Looking through the code in Listing 11-18 you'll see that the GridViewHeaderExtender class targets a GridView control by using the TargetControlType attribute. It also exposes a single property named WrapperDivCssClass that represents the CSS class that will be applied to the div that wraps the GridView control that will be extended. The extender class's WrapperDivCssClass property is mapped to the corresponding client-side property by using the Toolkit's ExtenderControlProperty and ClientPropertyName attributes. These two attributes greatly simplify the property mapping process especially compared to what is typically required when you use the ScriptControl and ScriptControlDescriptor classes discussed earlier in the chapter.

In addition to specifying which script should be output and mapping server-side properties to client-side properties, the GridViewHeaderExtender class also overrides OnPreRender to dynamically output two CSS classes into the page that are needed to help freeze the GridView header row so that it doesn't move when a user scrolls through rows. This is done by calling the CreateStyleRule method, which leverages two nested style classes embedded in the GridViewHeaderExtender class to generate the necessary CSS data.

11.2.4.3. Using an Extender Class in a Web Page

Once you've created an ASP.NET AJAX Control Toolkit extender class you can use it to extend controls in your Web applications. To extend a GridView control using the GridViewHeaderExtender class, create a new Web site in Visual Studio 2008 and reference the extender control project using Add Reference. Once the project is referenced, you can add a Register directive into the page to use the control as shown next:

<%@ Register  Assembly="GridViewHeaderDemo" Namespace="GridViewHeaderDemo"
    TagPrefix="toolkit" %>

Once the GridViewHeaderExtender control has been referenced, you'll need to define the CSS class that will be used to wrap the target GridView control (add borders around it if desired, set the height and width, plus more) in the page or in an external CSS stylesheet:

<style type="text/css">
    .WrapperDiv {
        width:800px;height:400px;border: 1px solid black;
    }
</style>

Finally, the GridViewHeaderExtender control can be added into the page. The GridView control that it targets can be assigned by using the TargetControlID property, and the CSS class that should be applied to the grid can be assigned by using the WrapperDivCssClass. Running the page will result in a $create method call being automatically output in the page; this is used to invoke the client-side Wrox.ASPAJAX.Samples.GridViewHeaderBehavior extender and freeze the GridView's header row.

<toolkit:GridViewHeaderExtender ID="gvExtender" runat="server"
 TargetControlID="GridView1" WrapperDivCssClass="WrapperDiv"/>

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset