ASP.NET Extender Control: Walkthrough

| Comments

Sample VS2008 Project is available at http://snipurl.com/asp_net_extendercontrol_sample.zip

This is the continuation  of ASP.NET Extender Control: Decorating & Componentizing Web Controls with Client Behavior.  In this walkthrough, the following things are explained:

  • Decorating or extending web control behavior.  A mouse hover effect which is implemented in JavaScript would be applied to controls of  type Button.
  • Packaging client side implementation along with the extender control assembly.

The client side implementation should consume  ASP.NET AJAX JavaScript API, in order to get the benefit of this.

As explained in previous section,  this walkthrough explains how to add mouse over and mouse out effect to controls of type Button.

Steps

  1. Implement decorator class based on ExtenderControl
  2. Implement client side behavior
  3. Make client side script as ASP.NET AJAX web resource
  4. Consume extender control

Decorator Class Implementation

Based on your application architecture and/or decorator usage, define the decorator class either within web project or separate assembly.  HoverExtension is the decorator class which extends ExtenderControl.

Based on figure 3 in the previous post, the following are the steps need to be completed:

  1. Define decorated properties in control
  2. Map control and client side properties
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections.Generic;

namespace Udooz
{
    [TargetControlType(typeof(Button))]
    public class HoverExtension : ExtenderControl
    {
        private string _hoverCssClass;

        public string HoverCssClass
        {
            get { return _hoverCssClass; }
            set { _hoverCssClass = value; }
        }
        private string _normalCssClass;

        public string NormalCssClass
        {
            get { return _normalCssClass; }
            set { _normalCssClass = value; }
        }

        protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors(Control targetControl)
        {
            ScriptBehaviorDescriptor descriptor = new ScriptBehaviorDescriptor("Udooz.HoverExtension", targetControl.ClientID);
            descriptor.AddProperty("hoverCssClass", this.HoverCssClass);
            descriptor.AddProperty("normalCssClass", this.NormalCssClass);           
            return new ScriptBehaviorDescriptor[] { descriptor };
        }

        protected override IEnumerable<ScriptReference> GetScriptReferences()
        {
            ScriptReference reference = new ScriptReference();
            reference.Assembly = "HoverExtension";
            reference.Name = "Udooz.HoverExtension.js";
            return new ScriptReference[] { reference };
        }
    }
}

Define decorated properties in control

The TargetControlTypeAttribute (line 10 ) enables to specify to which web controls this decorator can be applied.  HoverExtension can only be applied to Button type.  The next step is to define decorated properties for the server side so that it can be used in ASPX page. NormalCssClass and HoverCssClass are two properties defined to set style name for normal and hover state (line 15 – 26).

Map control and client side properties

As discussed in the previous post, the decorated class implements IExtenderControl’s methods GetScriptDescriptors (line 28-34) and GetScriptReferences (line 36-42).  The ScriptBehaviorDescriptor does two things here:

  • Based on the target server control given as an argument in the constructor, it specifies the client class to target control’s client ID (line 30).
  • Map the server side properties to client side properties (line 31, 32).

The ScriptReference is used to specify on which assembly the client behavior script file will be included (line 39) and the script file name (line 40).

Client Side Behavior Implementation

Based on figure 3 in the previous post, the following are the steps need to be completed those are implemented in HoverExtension.js:

  1. Define decorated properties for client side
  2. Implement client side behavior
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
 

Type.registerNamespace('Udooz');

Udooz.HoverExtension = function(element)
{
    Udooz.HoverExtension.initializeBase(this, [element]);

    this._hoverCssClass = null;
    this._normalCssClass = null;
}

Udooz.HoverExtension.prototype =
{
    initialize: function() {
        Udooz.HoverExtension.callBaseMethod(this, 'initialize');             
        $addHandlers(this.get_element(),
                     { 'mouseover': this._onMouseOver,
                         'mouseout': this._onMouseOut
                     },
                     this);

        this.get_element().className = this._normalCssClass;
    },

    dispose: function() {
        $clearHandlers(this.get_element());

        Udooz.HoverExtension.callBaseMethod(this, 'dispose');
    },

    _onMouseOver: function(e) {
        if (this.get_element() && !this.get_element().disabled) {
            this.get_element().className = this._hoverCssClass;
        }
    },

    _onMouseOut: function(e) {       
        if (this.get_element() && !this.get_element().disabled) {
            this.get_element().className = this._normalCssClass;
        }
    },

    get_hoverCssClass: function() {
        return this._hoverCssClass;
    },

    set_hoverCssClass: function(value) {
        if (this._hoverCssClass !== value) {
            this._hoverCssClass = value;
            this.raisePropertyChanged('hoverCssClass');
        }
    },

    get_normalCssClass: function() {
        return this._normalCssClass;
    },

    set_normalCssClass: function(value) {
        if (this._normalCssClass !== value) {
            this._normalCssClass = value;
            this.raisePropertyChanged('normalCssClass');
        }
    }
}

// Optional descriptor for JSON serialization.
Udooz.HoverExtension.descriptor = {
    properties: [{ name: 'hoverCssClass', type: String },
                    { name: 'normalCssClass', type: String}]
}

// Register the class as a type that inherits from Sys.UI.Control.
Udooz.HoverExtension.registerClass('Udooz.HoverExtension', Sys.UI.Behavior);

if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

A client side class Udooz.HoverExtension is defined.  The constructor initialize the given “element”.  The element reference is the target web control which will be given by ASP.NET at run time using ASP.NET AJAX $create() method.

Define decorated properties for client side

There are two properties normalCssClass (line 56-65) and hoverCssClass (line 45-54) defined.

Implement client side behavior

The mouse over and mouse out events are registered (line 17-21) and those handlers are defined (line 32-42).

Make Client Side Script As ASP.NET AJAX Web Resource

To package the HoverExtension.js into HoverExtension.dll, this script needs to be declared as web resource so that ASP.NET AJAX identifies and consumes this as web resource and invoke this via ScriptResource.axd handler.  In the AssemblyInfo.cs file of HoverExtension.dll, the following code needs to be added.

1
2
3
 

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

 

Consume Extender Control

Build the HoverExtension project and refer this into a ASP.NET 3.5 web project. The page should register HoverExtension type and can use wherever require.

 

1
<%@ Register Assembly="HoverExtension" Namespace="Udooz" TagPrefix="udooz" %>

Before consuming the control, the actual styles should be required.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 

<style type="text/css">
.Hover
{
    background-color:Red;
    border-color:Yellow;
}

.Normal
{
    background-color:Aqua;
    border-color:Blue;
}
</style>

 ASP.NET AJAX ScriptManager is required for runtime behaviors.

 

1
2
3
4
5
 
<pre>
 

<asp:ScriptManager ID="ScriptManager1" runat="server" />

 The actual button control definition and extender control usage would be

 

1
2
3
4
5
6
 
<pre>
 

<asp:Button ID="button" Text="Extended Button" runat="server" />       
<udooz:HoverExtension ID="extender1" HoverCssClass="Hover" NormalCssClass="Normal" TargetControlID="button" runat="server" /> 

When executing this page, ASP.NET AJAX creates the following for extension.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<span lang="EN">
<script type="text/javascript">

//<![CDATA[

Sys.Application.initialize();

Sys.Application.add_init(function() {

$create(Udooz.HoverExtension, {"hoverCssClass":"HighLight","normalCssClass":"LowLight"}, null, null, $get("button"));

});

//]]>

</script>