Update Panel .NET

Exploring Microsoft ASP.NET AJAX and jQuery

Archive for the ‘Microsoft AJAX Library’ Category

Microsoft AJAX Library Preview 6 Available

leave a comment »

Written by tzkuei

October 19, 2009 at 8:59 am

Goodbye Microsoft AJAX Library

with 4 comments

Microsoft AJAX Library is no more… for me!

No more Sys.<Whatever>!

I’ve seen the light, I shall jQuery all the way… to scripting heaven!

P.S. I may still use one or two JavaScript extensions (e.g. String.format) from the Microsoft AJAX Library!

Written by tzkuei

April 19, 2009 at 10:52 pm

Posted in Microsoft AJAX Library, jQuery

Tagged with

ASP.NET AJAX 4.0 Preview 4 Available

leave a comment »

ASP.NET AJAX 4.0 Preview 4 is available for download.

This release contains a preview version of the following features:

  •  
    • ADO.NET Data Services support
    • WCF and ASMX Web service integration
    • ASP.NET AJAX Client Templates
    • Declarative instantiation of client-side controls and behaviors
    • Observable pattern for plain JavaScript objects
    • Live Bindings
    • Markup Extensions
    • DataView control and DataContext component
    • Command Bubbling
    • Change tracking and identity management
    • Support for managing complex links and associations between entities from multiple entity sets or tables
    • Extension methods allowing change tracking and read-write client-server scenarios using other JSON services, including RESTful or JSONP based services

Written by tzkuei

April 1, 2009 at 8:15 am

More sugar for creating event accessors

leave a comment »

In my previous post I shared some sugar for creating property accessors. In this post I will share more sugar for creating event accessors.

So instead of writing:

MyNamespace.MyComponent.prototype = {
    ...
    add_change: function(handler) {
        this.get_events().addHandler("change", handler);
    },
    remove_change: function(handler) {
        this.get_events().removeHandler("change", handler);
    },
    ...
}

You just add:

MyNamespace.MyComponent.addEvent("change");

Here is the extra sugar:

Function.prototype.addEvent = function(name) {
    ///
<param name="name" type="String"></param>
    var e = Function._validateParams(arguments, [
        { name: "name", type: String }
    ]);
    if (e) throw e;
    this.addMethod("add_" + name, function(handler) {
        this.get_events().addHandler(name, handler);
    });
    this.addMethod("remove_" + name, function(handler) {
        this.get_events().removeHandler(name, handler);
    });
    this.addMethod("raise_" + name, function(args) {
        var handler = this.get_events().getHandler(name);
        if (handler) {
            handler(this, (args) ? args : Sys.EventArgs.Empty);
        }
    });
}

Type.addEvent(name)

Adds event accessors to the component “class”.

UPDATE: Added a raise_<eventName>(args) helper method.

Download Sugar.js from my SkyDrive.

Written by tzkuei

November 27, 2008 at 4:41 pm

Adding sweetness to the Microsoft AJAX Library

with 2 comments

A few months back, I reviewed some code by a colleague, and I noticed how she used helper functions to generate property accessors in component “classes”.  At first I dismissed her approach as unnecessary, but after writing property accessors for the n’th time, I have finally succombed to her way of thinking.

The simplest implementation of a property accessor looks something like this:

MyNamespace.MyComponent = function() {
    ...
    this._myProperty = 12345;
    ...
}
MyNamespace.MyComponent.prototype = {
    ...
    get_myProperty: function() {
        return this._myProperty;
    },
    set_myProperty: function(value) {
        this._myProperty = value;
    },
    ....
}

Wouldn’t it be nice if you don’t have to repeat that code for every property?  Well, you can create a Visual Studio code snippet to help with the typing, or add some sugar and write this instead:

MyNamespace.MyComponent = function() {
    ...
}
MyNamespace.MyComponent.addProperty("myProperty", 12345);

Here is the sugar:

Function.prototype.addField = function(name, value) {
    /// <param name="name" type="String"></param>
    /// <param name="value" mayBeNull="true"></param>
    /// <returns type="String"></returns>
    var e = Function._validateParams(arguments, [
        { name: "name", type: String },
        { name: "value", mayBeNull: true }
    ]);
    if (e) throw e;
    var fieldName = "_" + name;
    if (!(fieldName in this.prototype)) {
        this.prototype[fieldName] = value;
    }
    return fieldName;
}
Function.prototype.addMethod = function(name, method) {
    /// <param name="name" type="String"></param>
    /// <param name="method" type="Function"></param>
    var e = Function._validateParams(arguments, [
        { name: "name", type: String },
        { name: "method", type: Function }
    ]);
    if (e) throw e;
    if (!(name in this.prototype)) {
        this.prototype[name] = method;
    }
}
Function.prototype.addProperty = function(name, initialValue, raisePropertyChanged) {
    /// <param name="name" type="String"></param>
    /// <param name="initialValue" mayBeNull="true"></param>
    /// <param name="raisePropertyChanged" type="Boolean" optional="true"></param>
    var e = Function._validateParams(arguments, [
        { name: "name", type: String },
        { name: "initialValue", mayBeNull: true },
        { name: "raisePropertyChanged", type: Boolean, optional: true }
    ]);
    if (e) throw e;
    var fieldName = this.addField(name, initialValue);
    this.addMethod("get_" + name, function() {
        return this[fieldName];
    });
    if (raisePropertyChanged) {
        this.addMethod("set_" + name, function(value) {
            if (value !== this[fieldName]) {
                this[fieldName] = value;
                this.raisePropertyChanged(name);
            }
        });
    } else {
        this.addMethod("set_" + name, function(value) {
            this[fieldName] = value;
        });
    }
}

Save this script and include it in your page.  Because this script uses JavaScript extensions provided by the Microsoft AJAX Library, please ensure that is included first!  I suggest you use <asp:ScriptManager>.

For example:

<asp:ScriptManager runat="server">
    <Scripts>
        <asp:ScriptReference Path="Sugar.js" />
    </Scripts>
</asp:ScriptManager>

Type.addField(name, value)

Adds a property value field to your component “class”.

For example:

MyNamespace.MyComponent.addField("count", 1);

This is equivalent to:

MyNamespace.MyComponent = function() {
    ...
    this._count = 1;
    ...
}

Type.addMethod(name, method)

Adds a method to your component “class”.

For example:

MyNamespace.MyComponent.addMethod("sayHello", function (name) {
    alert("Hello " + name);
});

This is equivalent to:

MyNamespace.MyComponent.prototype = {
    sayHello: function(name) {
        alert("Hello " + name);
    }
}

Type._addGetter(name, method)

Adds a property getter method to your component “class”.  This method is for internal use only!

Type._addSetter(name, method)

Adds a property setter method to your component “class”.  This method is for internal use only!

While writing my next post, I decided to factor out the above two “internal” methods, as they don’t add much value.

Type.addProperty(name, initialValue, raisePropertyChanged)

Adds a property to your component “class”.  This includes the value field, the getter method and the setter method.

Parameters:

  • name – The name of the property, specified as a string in camel case.
  • initialValue – The initial value of the property.
  • raisePropertyChanged – A boolean to indicate whether you wish to raise the property changed event.

For example:

MyNamespace.MyComponent.addProperty("count", 1, true);

This is equivalent to:

MyNamespace.MyComponent = function() {
    ...
    this._count = 1;
    ...
}
MyNamespace.MyComponent.prototype = {
    ...
    get_count: function() {
        return this._count;
    },
    set_count: function(value) {
        if (value !== this._count) {
            this._count = value;
            this.raisePropertyChanged("count");
        }
    },
    ...
}

Download Sugar.js from my SkyDrive.

Written by tzkuei

November 26, 2008 at 3:45 pm

Image Corners Extender Control

with one comment

The prevalent use of styled borders (e.g. rounded corners) by our designers have caused much debate amongst the developers as to which technique should be employed to achieve the desired result.  The Backgrounds and Borders Module in CSS Level 3 would be ideal, but we have to wait until that becomes ubiquitous.

In this post, I present to you an extender control I created to add image corners to <asp:Panel> controls.  The extender works by injecting additional <div> elements into the DOM and style each with a background image.

Below is the source code for the server-side extender control:

using System.Collections.Generic;
using System.Web.UI;
using System.Web.UI.WebControls;
[assembly: WebResource("UPDN.ImageCornersBehavior.js", "text/javascript")]
namespace UPDN
{
    ///

    /// Summary description for ImageCornersExtender
    ///

    [TargetControlType(typeof(Panel))]
    public class ImageCornersExtender : ExtenderControl
    {
        public string TopBorderImageUrl { get; set; }
        public string RightBorderImageUrl { get; set; }
        public string BottomBorderImageUrl { get; set; }
        public string LeftBorderImageUrl { get; set; }
        public string TopLeftCornerImageUrl { get; set; }
        public string TopRightCornerImageUrl { get; set; }
        public string BottomLeftCornerImageUrl { get; set; }
        public string BottomRightCornerImageUrl { get; set; }
        public string MiddleImageUrl { get; set; }
        protected override IEnumerable GetScriptDescriptors(Control targetControl)
        {
            var descriptor = new ScriptControlDescriptor(“UPDN.ImageCornersBehavior”, targetControl.ClientID);
            var imageUrls = new Dictionary();
            if (!string.IsNullOrEmpty(TopBorderImageUrl))
                imageUrls.Add(“t”, TopBorderImageUrl);
            if (!string.IsNullOrEmpty(RightBorderImageUrl))
                imageUrls.Add(“r”, RightBorderImageUrl);
            if (!string.IsNullOrEmpty(BottomBorderImageUrl))
                imageUrls.Add(“b”, BottomBorderImageUrl);
            if (!string.IsNullOrEmpty(LeftBorderImageUrl))
                imageUrls.Add(“l”, LeftBorderImageUrl);
            if (!string.IsNullOrEmpty(TopLeftCornerImageUrl))
                imageUrls.Add(“tl”, TopLeftCornerImageUrl);
            if (!string.IsNullOrEmpty(TopRightCornerImageUrl))
                imageUrls.Add(“tr”, TopRightCornerImageUrl);
            if (!string.IsNullOrEmpty(BottomLeftCornerImageUrl))
                imageUrls.Add(“bl”, BottomLeftCornerImageUrl);
            if (!string.IsNullOrEmpty(BottomRightCornerImageUrl))
                imageUrls.Add(“br”, BottomRightCornerImageUrl);
            if (!string.IsNullOrEmpty(MiddleImageUrl))
                imageUrls.Add(“m”, MiddleImageUrl);
            descriptor.AddProperty(“imageUrls”, imageUrls);
            yield return descriptor;
        }
        protected override IEnumerable GetScriptReferences()
        {
            yield return new ScriptReference(“UPDN.ImageCornersBehavior.js”, this.GetType().Assembly.FullName);
        }
    }
}

And the source code for the client-side behavior:

Type.registerNamespace("UPDN");
UPDN.ImageCornersBehavior = function(element) {
    UPDN.ImageCornersBehavior.initializeBase(this, [element]);
    // keys: t, l, b, r, tl, tr, bl, br
    this._imageUrls = null;
}
UPDN.ImageCornersBehavior.prototype = {
    initialize: function() {
        UPDN.ImageCornersBehavior.callBaseMethod(this, "initialize");
        var el = this.get_element();
        var imagesUrls = this.get_imageUrls();
        var containers = [];
        // create border elements
        if (imagesUrls["t"]) {
            var t = document.createElement("div");
            t.style.background = "url(" + imagesUrls["t"] + ") repeat-x top left";
            containers.push(t);
        }
        if (imagesUrls["r"]) {
            var r = document.createElement("div");
            r.style.background = "url(" + imagesUrls["r"] + ") repeat-y top right";
            containers.push(r);
        }
        if (imagesUrls["b"]) {
            var b = document.createElement("div");
            b.style.background = "url(" + imagesUrls["b"] + ") repeat-x bottom left";
            containers.push(b);
        }
        if (imagesUrls["l"]) {
            var l = document.createElement("div");
            l.style.background = "url(" + imagesUrls["l"] + ") repeat-y top left";
            containers.push(l);
        }
        if (imagesUrls["tl"]) {
            var tl = document.createElement("div");
            tl.style.background = "url(" + imagesUrls["tl"] + ") no-repeat top left";
            containers.push(tl);
        }
        if (imagesUrls["tr"]) {
            var tr = document.createElement("div");
            tr.style.background = "url(" + imagesUrls["tr"] + ") no-repeat top right";
            containers.push(tr);
        }
        if (imagesUrls["bl"]) {
            var bl = document.createElement("div");
            bl.style.background = "url(" + imagesUrls["bl"] + ") no-repeat bottom left";
            containers.push(bl);
        }
        if (imagesUrls["br"]) {
            var br = document.createElement("div");
            br.style.background = "url(" + imagesUrls["br"] + ") no-repeat bottom right";
            containers.push(br);
        }
        if (containers.length > 0) {
            // create content container
            var m = document.createElement("div");
            m.className = "content";
            // move child elements of target element into content container
            this._moveChildren(el, m);
            // set middle image as background of target element
            if (imagesUrls["m"]) {
                el.style.background = "url(" + imagesUrls["m"] + ") repeat top left";
            }
            containers.push(m);
            // inject containers into DOM
            el.appendChild(containers[0]);
            for (var i = 1; i < containers.length; i++) {
                containers[i - 1].appendChild(containers[i]);
            }
        }
    },
    dispose: function() {
        //Add custom dispose actions here
        UPDN.ImageCornersBehavior.callBaseMethod(this, "dispose");
    },
    _moveChildren: function(srcEl, destEl) {
        while (srcEl.hasChildNodes()) {
            var child = srcEl.childNodes[0];
            destEl.appendChild(child);
        }
    },
    get_imageUrls: function() {
        return this._imageUrls;
    },
    set_imageUrls: function(value) {
        this._imageUrls = value;
    }
}
UPDN.ImageCornersBehavior.registerClass("UPDN.ImageCornersBehavior", Sys.UI.Behavior);

To use the extender, place an <asp:Panel> control on the page:

<asp:Panel ID="Panel1" runat="server" CssClass="box1">
    This box is styled using 8 images. Lorem ipsum no etiam perfecto his, per adhuc maiorum epicurei eu. Laoreet signiferumque in mel, ne vel dicat percipit instructior. An eum veniam decore perpetua, nam laudem praesent at. Exerci accumsan contentiones est ei, appetere gloriatur et qui, ea suscipit senserit consectetuer mei.
</asp:Panel>

Then add the extender, set the TargetControlID to the ID of the <asp:Panel> control, and specify the images required to achieve your design. For this panel, I require eight images, four for the borders and four for the corners:

b bl br l r t tl tr
<updn:ImageCornersExtender ID="ImageCornersExtender1" runat="server"
    TargetControlID="Panel1"
    TopBorderImageUrl="img/box1/t.gif"
    RightBorderImageUrl="img/box1/r.gif"
    BottomBorderImageUrl="img/box1/b.gif"
    LeftBorderImageUrl="img/box1/l.gif"
    TopLeftCornerImageUrl="img/box1/tl.gif"
    TopRightCornerImageUrl="img/box1/tr.gif"
    BottomLeftCornerImageUrl="img/box1/bl.gif"
    BottomRightCornerImageUrl="img/box1/br.gif"
/>

Here is how the complete example looks like:

Image borders examples

Download the source code and example from my SkyDrive.

Written by tzkuei

November 25, 2008 at 11:04 am

How to get a reference to a Sys.UI.Behavior instance

leave a comment »

If you attach a behavior to an element, how do you get a reference to it?

For example, on this page, there is a text box control with two behaviors attached:

<asp:TextBox ID="txtTitle" runat="server" />
<ajax:TextBoxWatermarkExtender BehaviorID="titleWatermark" TargetControlID="txtTitle" ... />
<ajax:AutoCompleteExtender TargetControlID="txtTitle" ... />

To access the client-side behaviors, you can use one of three static methods in Sys.UI.Behavior:

Sys.UI.Behavior.getBehaviorByName(element, name)

This method gets a Sys.UI.Behavior instance with the specified name property from the specified HTML Document Object Model (DOM) element.

var behavior = Sys.UI.Behavior.getBehaviorByName($get("txtTitle"), "TextBoxWatermarkBehavior");

Returns the the TextBoxWatermarkBehavior.

N.B. By default, the name of a behavior is its type, unless you explicitly specify one.

An expando attribute with the same name is created on the element, therefore, you can also access the behavior by:

var behavior = $get("txtTitle").TextBoxWatermarkBehavior;

Sys.UI.Behavior.getBehaviorsByType(element, type)

This method gets an array of Sys.UI.Behavior objects that are of the specified type from the specified HTML Document Object Model (DOM) element.

var behaviors = Sys.UI.Behavior.getBehaviorsByType($get("txtTitle"), AjaxControlToolkit.AutoCompleteBehavior);

Returns an array containing one behavior – the AutoCompleteBehavior.

N.B. This method is incorrectly named as getBehaviorByType (singular behavior) on MSDN, the actual name is getBehaviorsByType (plural behavior) as from the library source code!

Sys.UI.Behavior.getBehaviors(element)

This method gets an array of Sys.UI.Behavior objects that are associated with the specified HTML Document Object Model (DOM) element.

var behaviors = Sys.UI.Behavior.getBehaviors($get("txtTitle"));

Returns an array containing two behaviors - the TextBoxWatermarkBehavior and the AutoCompleteBehavior.

BehaviorID and Sys.Application.findComponent(id)

All the extenders in the AJAX Control Toolkit has a BehaviorID property, and if you set it to a unique string, you can use Sys.Application.findComponent(id) or simply $find(id) to get at the behavior.

var behavior = $find("titleWatermark");

Also see Getting a reference to a behavior by Bertrand Le Roy.

Written by tzkuei

November 23, 2008 at 11:13 pm

ComboBox control added to the ASP.NET AJAX Control Toolkit

with 5 comments

The latest changeset from CodePlex includes a new ComboBox control.

This is what the example looks like:

Screen capture of ComboBox example

Written by tzkuei

November 20, 2008 at 2:10 pm

Getting started with Sys.Binding – Part 3

leave a comment »

In part one, I demonstrated how Sys.Binding can be used to bind properties of DOM elements, and in part two, I used a simple JavaScript object to share properties across multiple DOM elements.  In this post, I will expand on the topic by adding components to the mix.  By components I mean objects derived from Sys.Component, that includes Sys.UI.Behavior and Sys.UI.Control.

Sys.Binding works with components by hooking up the propertyChanged event to track changes made to the bound properties, and gets or sets values by invoking the relevant getter and setter functions.

As for the example, I will expand on the one given in part two, and add a slider to allow the user to adjust the range by dragging on the handles, like this:

Screen capture of example

I know there is a slider control in the AJAX Control Toolkit, but it currently does not support multiple handles, and I need two for this example.  I also know there is a MultiHandleSlider control in development, but I need it now!

Well, jQuery UI has a nice slider control that already supports multiple handles, so I will be using it for my example.  Download the 1.5.2 stable build, unzip the archive and add the folder to your web site:

Web site project structure

There is a “slight” problem – the jQuery UI slider cannot be used directly with Sys.Binding, becuase it does not have the necessary property getter and setter functions, i.e. get_value() and set_value(), nor the “propertyChanged” event, required by Sys.Binding.  As a workaround, I wrapped the jQuery UI slider inside a Sys.UI.Control:

Type.registerNamespace("UPDN.jQuery.UI");
UPDN.jQuery.UI.Slider = function(element) {
    UPDN.jQuery.UI.Slider.initializeBase(this, [element]);
    this._slider = $(element);
    this._animate = false;
    this._enabled = true;
    this._handles = [];
    this._max = 100;
    this._min = 0;
    this._orientation = "horizontal";
    this._range = false;
    this._stepping = 0;
    this._steps = 0;
}
UPDN.jQuery.UI.Slider.prototype = {
    initialize: function() {
        var options = {
            animate: this.get_animate(),
            axis: this.get_orientation(),
            handles: this.get_handles(),
            max: this.get_max(),
            min: this.get_min(),
            range: this.get_range(),
            steps: this.get_steps(),
            change: Function.createDelegate(this, this._raiseChangeEvent),
            slide: Function.createDelegate(this, this._raiseSlideEvent),
            start: Function.createDelegate(this, this._raiseStartEvent),
            stop: Function.createDelegate(this, this._raiseStopEvent)
        }
        this._slider.slider(options);
        // Dynamically add value property getter and setter for each handle
        // Property name is "value" + handle.id, as specified in the options.
        // If handle.id is "1" then property is get_value1() and set_value1(value).
        var handles = this.get_handles();
        for (var i = 0; i < handles.length; i++) {
            this._addValueProperty(i, handles[i]);
        }
    },
    dispose: function() {
        this._slider.slider("destroy");
    },
    _addValueProperty: function(i, handle) {
        var propertyName = "value" + handle.id;
        this["get_" + propertyName] = function(index) {
            return function() {
                return this.getValue(index);
            }
        } (i);
        this["set_" + propertyName] = function(index) {
            return function(value) {
                this.setValue(index, value);
            }
        } (i);
        this.add_slide(Function.createDelegate(this, function() {
            this.raisePropertyChanged(propertyName);
        }));
    },
    _raiseChangeEvent: function() {
        var handler = this.get_events().getHandler("change");
        if (handler) {
            handler(this, Sys.EventArgs.Empty);
        }
    },
    _raiseSlideEvent: function() {
        var handler = this.get_events().getHandler("slide");
        if (handler) {
            handler(this, Sys.EventArgs.Empty);
        }
    },
    _raiseStartEvent: function() {
        var handler = this.get_events().getHandler("start");
        if (handler) {
            handler(this, Sys.EventArgs.Empty);
        }
    },
    _raiseStopEvent: function() {
        var handler = this.get_events().getHandler("stop");
        if (handler) {
            handler(this, Sys.EventArgs.Empty);
        }
    },
    add_change: function(handler) {
        /// <summary>Adds a event handler for the change event.</summary>
        /// <param name="handler" type="Function">The handler to add to the event.</param>
        this.get_events().addHandler("change", handler);
    },
    remove_change: function(handler) {
        /// <summary>Removes a event handler for the change event.</summary>
        /// <param name="handler" type="Function">The handler to remove from the event.</param>
        this.get_events().removeHandler("change", handler);
    },
    add_slide: function(handler) {
        /// <summary>Adds a event handler for the slide event.</summary>
        /// <param name="handler" type="Function">The handler to add to the event.</param>
        this.get_events().addHandler("slide", handler);
    },
    remove_slide: function(handler) {
        /// <summary>Removes a event handler for the slide event.</summary>
        /// <param name="handler" type="Function">The handler to remove from the event.</param>
        this.get_events().removeHandler("slide", handler);
    },
    add_start: function(handler) {
        /// <summary>Adds a event handler for the start event.</summary>
        /// <param name="handler" type="Function">The handler to add to the event.</param>
        this.get_events().addHandler("start", handler);
    },
    remove_start: function(handler) {
        /// <summary>Removes a event handler for the start event.</summary>
        /// <param name="handler" type="Function">The handler to remove from the event.</param>
        this.get_events().removeHandler("start", handler);
    },
    add_stop: function(handler) {
        /// <summary>Adds a event handler for the stop event.</summary>
        /// <param name="handler" type="Function">The handler to add to the event.</param>
        this.get_events().addHandler("stop", handler);
    },
    remove_stop: function(handler) {
        /// <summary>Removes a event handler for the stop event.</summary>
        /// <param name="handler" type="Function">The handler to remove from the event.</param>
        this.get_events().removeHandler("stop", handler);
    },
    get_animate: function() {
        /// <value type="Boolean">True if slider handle animation is enabled, false if disabled.</value>
        return this._animate;
    },
    set_animate: function(value) {
        this._animate = value;
    },
    get_enabled: function() {
        /// <value type="Boolean">True if slider is enabled, false if disabled.</value>
        return this._enabled;
    },
    set_enabled: function(value) {
        if (this._enabled !== value) {
            this._enabled = value;
            if (value) {
                this._slider.slider("enable");
            } else {
                this._slider.slider("disable");
            }
            this.raisePropertyChanged("enabled");
        }
    },
    get_handles: function() {
        /// <value type="Object">Specify boundaries for one or more handles.</value>
        return this._handles;
    },
    set_handles: function(value) {
        this._handles = value;
    },
    get_max: function() {
        /// <value type="Number">The maximum value of the slider.</value>
        return this._max;
    },
    set_max: function(value) {
        this._max = value;
    },
    get_min: function() {
        /// <value type="Number">The minimum value of the slider.</value>
        return this._min;
    },
    set_min: function(value) {
        this._min = value;
    },
    get_orientation: function() {
        /// <value type="String">The orientation of the slider.</value>
        return this._orientation;
    },
    set_orientation: function(value) {
        this._orientation = value;
    },
    get_range: function() {
        /// <value type="Boolean">True if slider range is enabled, false if disabled.</value>
        return this._range;
    },
    set_range: function(value) {
        this._range = value;
    },
    get_stepping: function() {
        /// <value type="Number">The number to jump per slide.</value>
        return this._stepping;
    },
    set_stepping: function(value) {
        this._stepping = value;
    },
    get_steps: function() {
        /// <value type="Number">The number of steps the slider have.</value>
        return this._steps;
    },
    set_steps: function(value) {
        this._steps = value;
    },
    getValue: function(index) {
        /// <summary>Gets the current value of the specified handle.</summary>
        /// <param name="index" type="Number">The index/number of the handle, zero-based.</param>
        return this._slider.slider("value", index);
    },
    setValue: function(index, value) {
        /// <summary>Sets the value of the specified handle.</summary>
        /// <param name="index" type="Number">The index/number of the handle, zero-based.</param>
        /// <param name="value" type="Number">The value to be set.</param>
        this._slider.slider("moveTo", value, index);
    }
}
UPDN.jQuery.UI.Slider.registerClass("UPDN.jQuery.UI.Slider", Sys.UI.Control);

Save this script as UPDN.jQuery.UI.Slider.js and add it the web site project.

By wrapping the jQuery UI slider inside a Sys.UI.Control, I have exposed the necessary property getters and setters and hooked up the “slide” event to raise the propertyChanged event whenever the user moves the slider handle(s).

Include a few stylesheets to the page, between the <head> tags:

<link href="jquery.ui-1.5.2/themes/flora/flora.css" rel="stylesheet" type="text/css" />
<link href="jquery.ui-1.5.2/themes/flora/flora.slider.css" rel="stylesheet" type="text/css" />
<style type="text/css" media="all">
#Slider1 { margin-top: 1.5em; }
.label-1 { position: absolute; left: 0; top: -1.1em; }
.label-2 { position: absolute; right: 0; top: -1.1em; }
</style>

Add the <asp:ScriptManager> control and include the necessary scripts:

<asp:ScriptManager ID="ScriptManager1" runat="server">
    <Scripts>
        <asp:ScriptReference Path="~/MicrosoftAjaxTemplates.js" ScriptMode="Auto" />
        <asp:ScriptReference Path="~/jquery.ui-1.5.2/jquery-1.2.6.js" ScriptMode="Auto" />
        <asp:ScriptReference Path="~/jquery.ui-1.5.2/ui/ui.core.js" ScriptMode="Auto" />
        <asp:ScriptReference Path="~/jquery.ui-1.5.2/ui/ui.slider.js" ScriptMode="Auto" />
        <asp:ScriptReference Path="~/UPDN.jQuery.UI.Slider.js" ScriptMode="Auto" />
    </Scripts>
</asp:ScriptManager>

Add the mark-up for the slider to the page:

<asp:CheckBox ID="CheckBox1" runat="server" Text="Use slider" Checked="true" />
<div id="Slider1" class="ui-slider-2">
    <span class="label-1">0</span>
    <span class="label-2">100</span>
</div>

Add the following blocks of JavaScript to the pageLoad() function:

var slider = $create(UPDN.jQuery.UI.Slider, {
    handles: [ { start: 0, min: 0, max: 100, id: "1" },
               { start: 100, min: 0, max: 100, id: "2" } ],
    range: true
}, null, null, $get("Slider1"));

This block creates the slider component, and assigns it the the slider variable for later usage.

$create(Sys.Binding, {
    target: slider,
    targetProperty: "enabled",
    source: $get("CheckBox1"),
    path: "checked",
    mode: Sys.BindingMode.oneWay
});

This block creates the binding between the check box element and the “enabled” property of the slider component, so the user can enable or disable the slider by selecting the check box.

$create(Sys.Binding, {
    target: slider,
    targetProperty: "value1",
    source: range,
    path: "min",
    mode: Sys.BindingMode.twoWay
});
$create(Sys.Binding, {
    target: slider,
    targetProperty: "value2",
    source: range,
    path: "max",
    mode: Sys.BindingMode.twoWay
});

This blocks binds the slider handles to the range JavaScript object.

Start the web site and you should be able to change the min and max values by entering a value into the text boxes or moving the handles on the slider, and watch the changes reflected in all the bound elements.

Written by tzkuei

November 16, 2008 at 10:58 pm

Posted in Microsoft AJAX Library

Tagged with ,

New controls in the ASP.NET AJAX Control Toolkit

leave a comment »

I downloaded the latest changeset from CodePlex, and what I found in the Release directory are three new controls:

  • ColorPicker
    ColorPicker example
  • MultiHandleSlider
    MultiHandleSlider example
  • RichTextEditor
    RichTextEditor example

You can also find a few other community contributions in the Prototype folder:

  • AnimatedSiteMapMenu
  • Balloon
  • BalloonPopup
  • Callout
  • ContextMenu
  • FormattedTextBox
  • Picker
  • TextCount
  • Tooltip

Hopefully, some of these controls will be released with ASP.NET 4.0 as mentioned by Bertrand Le Roy in his PDC presentation – ASP.NET AJAX Futures.

Written by tzkuei

November 15, 2008 at 12:57 pm