Archive for the ‘Microsoft AJAX Library’ Category
Microsoft AJAX Library Preview 6 Available
Yeah, new stuff to play with!
Read more about this release:
Goodbye Microsoft AJAX Library
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!
ASP.NET AJAX 4.0 Preview 4 Available
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
More sugar for creating event accessors
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.
Adding sweetness to the Microsoft AJAX Library
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.
Image Corners Extender Control
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
{
///
///
[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
{
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
{
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:
<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:

Download the source code and example from my SkyDrive.
How to get a reference to a Sys.UI.Behavior instance
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.
ComboBox control added to the ASP.NET AJAX Control Toolkit
The latest changeset from CodePlex includes a new ComboBox control.
This is what the example looks like:
Getting started with Sys.Binding – Part 3
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:
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:
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.
New controls in the ASP.NET AJAX Control Toolkit
I downloaded the latest changeset from CodePlex, and what I found in the Release directory are three new controls:
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.




