Introduction
Couple of weeks ago, I created a DHTML control, based on the DHTML posted on www.dynamicdrive.com. It was a data-bound control, and it was a nice experience. I had to go through all the details of amazing "Developing Microsoft ASP.NET Server Controls and Components", and I learnt a lot of new things. But, after I start reading about AjaxControlToolkit, and started analyzing the code, I realized that there is a lot easier way to achieve the same thing, in a lot more elegant way.
Background
The control, basically displays some HTML, the displayed HTML fades, and it's replaced with another. The control has to be templated, and data-bound. The ideal base for this requirement was AjaxControlToolkit's Accordion control. It's one of the more complicated controls, but it has everything I needed. The fading effect of the Animation extender I used is really one of the simplest, but still, it gives us the perfect way to start delving into this area of AJAX.
Using the code
You can use the scroller as a full featured data-bound control, or you can enter the content to be scrolled declaratively or programmatically, in the code. These are the steps:
- Create an AJAX enabled web site
- Add a reference to
Scroller
and AjaxControlToolkit
assemblies, located in the bin folder of the Scroller
control - Register
Scroller
on the web page:
<%@ Register Assembly="Scroller" Namespace="AjaxScroller"
TagPrefix="cc1" %>
- Add
Scroller
to the page:
<cc1:scroller id="Sc1" runat="server"
contentcssclass="ScrollerPaneStyle"
cssclass="ScrollerStyle">
<cc1:scroller>
- Add
<Panes>
tag - Add as many
Scroller
panes as you like:
<cc1:ScrollerPane runat="server" ID="p1">
<Content>
Some text to be scrolled <br />
</Content>
</cc1:ScrollerPane>
If you want to bind the scroller to the data source, the code should look like this:
<cc1:Scroller ID="Scroller2" runat="server" DataSourceID="SqlDataSource1"
CssClass="ScrollerStyle" ContentCssClass="ScrollerPaneStyle" >
<Panes></Panes>
<ContentTemplate>
<h2>The description of categorie <%# Eval("CategoryName") %>
<br /></h2>
<%# Eval("Description")%>
</ContentTemplate>
</cc1:Scroller>
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="
<%$ ConnectionStrings:NorthwindConnectionString %>"
SelectCommand="SELECT * FROM [Categories]">
</asp:SqlDataSource>
This Scroller
is bound to the Northwind Categories description field(you will have to change the connection string in the web.config).
The most interesting properties of the Scroller
are:
TransitionDuration
– how long will the fading between panes last (default is 1000 ms), FramesPerSecond
– default is 30, and ContentCssClass
– which define the style of the content to be scrolled.
Control
Scroller
is not an extender control. Instead, it uses an extender internally to extend its behavior. Like I said in the background, the control uses Accordion AjaxcControlToolkit control like its model. I won't go deep into explanation of this control, because it will need a lot more than one article, but I will briefly explain all the component classes, and the most interesting points. Accordion control is a good model for creating a templated data-bound control, and most of the pattern is general. I just removed the parts which I don't need (Header template), added couple of things (additional div, so fading will not affect the border of the control, if it's present), and, the internal extender JavaScript had to be completely changed. I didn't remove event items related classes, because, in future scenarios, I could use this fast and easy. Just not to be confused with the code, ScrollerCommandEventArgs.cs and ScrollerItemEvent.cs are not used, and are here if you wish to add some additional functionality.
Classes
ScrollerContentPanel
This is a content pane in which the template will be instantiated. It follows a data-bound pattern, and the only deference from AccordationContentPanel
is property InVisible
, which will set display style of the panel (div) to "none
" or "block
". All the panels are invisible when the control is created, and the visibility is controlled in AjaxScrollerExtender.js. Like I said, there is OnBubbleEvent
override, which is not used, but it's here for future use. This pane will be actually scrolled (faded) by the AJAX extender.
ScrollerPane
This is the container for the ScrollerContentPane
, and it has one template – Content
, which is instantiated in the ScrollerContentPane
member – ContentContainer
. Originally, Accordion control had one more template – Header
, which is not needed for our Fading Scroller. The interesting point in this control is that it actually doesn't render begin/end tags, by overriding RenderBeginTag/RenderEndTag
.
ScrollerPaneCollection
This is a collection of all ScrollerPanes
which implements IList
and IEnumerable
. I didn't change anything in this class, except, of course, the type of the objects this collection contains.
Scroller
This the most interesting of all classes. The bulk of the control is standard code for the templated, data-bound control. The point I want to emphasize is - how to use extender to extend your control? Before that, let's first explain the actual extender which is used to extend Scroller
. The name of the extender class is AjaxScrollerExtender
. The AjaxScrollerExtender
just defines the properties of the extender, and AjaxScrollerDesigner
is doing a simple design time representation of the control. I will show the full AjaxScrollerBegaviour.js code, which has comments that will help you to go through it:
Type.registerNamespace('AjaxScroller');
AjaxScroller.AjaxScrollerBehavior = function(element)
{
AjaxScroller.AjaxScrollerBehavior.initializeBase(this, [element]);
this._framesPerSecond = 30;
this._duration = 1;
this._panes = [];
this._currentPane = 0;
this._fadeAnimation = null;
this._fadeIn = null;
this._fadeOut = null;
this._hoverOverHendler = null;
this._hoverOutHendler = null;
this._endedHandler = null;
}
AjaxScroller.AjaxScrollerBehavior.prototype =
{
initialize : function() {
AjaxScroller.AjaxScrollerBehavior.callBaseMethod(this, 'initialize');
var e = this.get_element();
var firstchildren = e.childNodes;
for (var i = 0; i < firstchildren.length; i++) {
var child = firstchildren[i];
if (child.nodeType == 1) {
firstDiv = child;
break;
}
}
var children = firstDiv.childNodes;
for (var i = 0; i < children.length; i++) {
var child = children[i];
if (child.nodeType == 1) {
Array.add(this._panes, child);
}
}
if (this._panes.length > 0)
{
this._fadeIn = new AjaxControlToolkit.Animation.FadeInAnimation
(firstDiv, this._duration, this._framesPerSecond, 0, 1, true);
this._fadeOut = new AjaxControlToolkit.Animation.FadeOutAnimation
(firstDiv, this._duration, this._framesPerSecond, 0, 1, true);
this._fadeAnimation =
new AjaxControlToolkit.Animation.SequenceAnimation
(firstDiv, this._duration, this._framesPerSecond,
[this._fadeIn, this._fadeOut], 1);
this._endedHandler = Function.createDelegate(this, this._switchDiv);
this._fadeAnimation.add_ended(this._endedHandler);
this._hoverOverHendler = Function.createDelegate(this, this._hoverOver);
this._hoverOutHendler = Function.createDelegate(this, this._hoverOut);
$addHandlers(e, {
mouseover: this._hoverOverHendler,
mouseout: this._hoverOut,
focus: this._hoverOverHendler,
blur: this._hoverOut
}, this);
this._panes[this._currentPane].style.display = "block";
this._fadeAnimation.play();
}
},
dispose : function()
{
if (this._endedHandler)
{
this._fadeAnimation.remove_ended(this._endedHandler);
this._endedHandler = null;
}
$clearHandlers(this.get_element());
AjaxScroller.AjaxScrollerBehavior.callBaseMethod(this, 'dispose');
},
_switchDiv : function()
{
var currentPane = this._panes[this._currentPane];
currentPane.style.display = "none";
this._currentPane++;
if (this._currentPane == this._panes.length) this._currentPane = 0;
var nextPane = this._panes[this._currentPane];
nextPane.style.display = "block";
this._fadeAnimation.play();
},
_hoverOver: function()
{
this._fadeAnimation.pause();
},
_hoverOut: function()
{
this._fadeAnimation.stop();
this._fadeAnimation.play();
},
.....
So, back to the point – how do you use this extender to extend your control! Just declare the private
AjaxScrollerExtender
property in your control, and then in CreateChildControls
override it , assign it an ID, and set the TargetControlID
to the ID of your control:
_extender = new AjaxScrollerExtender();
_extender.ID = ID + "_ScrollerExtender";
_extender.TargetControlID = ID;
if (!this.DesignMode)
Controls.AddAt(0, _extender);
Points of Interest
The main point of this article is how easily you can create full featured AJAX controls. This control can be pretty easily extended to use a lot more sophisticated AJAX animations for creation of different text effects. For instance, adding color animation can be done with just a couple of lines. Animation extender from the AJAX Control Toolkit gives you a very strong base, and the only limit is your creativity.