Saturday, February 04, 2012   Click here to search  
Welcome: Register | Login
You Are Here » Forums
 
Orlando DotNetNuke® Users Group (ODUG) Forums
 
 
HomeHomeGeneralGeneralHow To, Tips & ...How To, Tips & ...Autogeneration of Client-side JavaScript from an ASP.NET User ControlAutogeneration of Client-side JavaScript from an ASP.NET User Control
Previous
 
Next
New Post
12/3/2009 11:07 AM
 

Kirk Marple

Implementing image preloading for ASP.NET ImageButton controls


I was recently tracking down a bug with JavaScript onMouseOut/onMouseOver handlers in my ASP.NET User Controls. In order to rule out one possible problem -- images that haven't been downloaded yet -- I decided it would be useful to implement image preloading for my ASP.NET ImageButton controls.

I've seen the slick way that Macromedia Dreamweaver inserts the MM_preloadImages() function in its authored pages. So, I thought... there must be a way in my ASP.NET pages to do the same thing. After a little bit of research, I found that there was a way, and it was pretty easy to implement.

The Solution

In my ASP.NET application, I've created a base class for all User Controls called BaseUserControl. BaseUserControl inherits from System.Web.UI.UserControl, and all my application-specific User Controls inherit from BaseUserControl. In the constructor of all application-specific User Controls, I have them set their ID to the class name (i.e. "OrdersListControl"). This makes it easy for debugging later, so the base class methods can know what class they are running in.

On many of my User Controls, I have ImageButton server controls which build client-side image elements with mouse-over states. In the onMouseOver client-side event, I've used the JavaScript below to store away the current image file name and flip to the mouse-over state image file name. In the onMouseOut event, I flip the image source back to the original image file name.

NOTE: I've found that you must check the oldsrc property for null before using it, because there can be times when the onMouseOut event will fire without a preceding onMouseOver event.

You'll notice that I've added the mouse-over state image file name as an attribute (oversrc) within the ImageButton control. This will allow us to easily parse out the mouse-over image file name, as well as to generalize the JavaScript event handlers.

In order to preload the images for the User Control, I realized that I would need to parse the ImageButton controls for the image file names before the page is rendered, auto-generate the JavaScript, and write it into the rendered page.

PreRender event

The first step was to create an event handler for the PreRender event.

From the ASP.NET documentation:

[C#] public event EventHandler PreRender;

I added the PreRender event to my User Control in the constructor.

this.PreRender += new System.EventHandler(Page_PreRender);

In my Page_PreRender() method, I will be able to walk the object model of the Page and parse out anything I need for rendering the page.

RegisterStartupScript

I am using the RegisterStartupScript() method to write the JavaScript into the page, so it will get executed as the page loads.

[C#] public virtual void RegisterStartupScript(string key, string script );

Since the User Control can be loaded multiple times within a page, I want to check that this startup script hasn't been registered already. I have made the name of the startup script by appending the User Control ID with the text "_preload_images".

[C#] public bool IsStartupScriptRegistered( string key );

JavaScript Generation

In the Page_PreRender() method, I enumerate the Controls collection of the User Control. For each control, I check if it is an ImageButton control. If it is, I grab the default state image file name which is held in the ImageUrl property, and I grab the mouse-over state image file name, which is held in the oversrc attribute.

NOTE: I am using a StringBuilder class to store the generated JavaScript.

Given these two filenames, I can generate the JavaScript Image object creation code, as well as the assignment of the file name to the src property.

sb_back.Append(@"preload_images[" + iCount.ToString() + "] = new Image();"); sb_back.Append(@"preload_over_images[" + iCount.ToString() + "] = new Image();"); sb_back.Append(@"preload_images[" + iCount.ToString() + "].src = '" + sURL + "'; \n"); sb_back.Append(@"preload_over_images[" + iCount.ToString() + "].src = '" + sOverURL + "'; \n");

When I'm done enumerating all controls, the iCount variable holds the number of ImageButton controls.

In order to easily assemble the JavaScript, I've broken the script generation into a front and back section. The StringBuilder sb_front needs the value of iCount to generate the array dimension for the preload_images and preload_over_images arrays. The StringBuilder sb_back contains the list of Image objects.

If iCount is greater than zero, we have generated one JavaScript Image objects, and we will register the startup script with the concatenation of the sb_front and sb_back StringBuilder variables.

Here is the resulting JavaScript for the ImageButton above:

Summary

That's all there is to it. I hope I've shown you an easy way to walk the object model of an ASP.NET page and dynamically generate client-side content. The major pieces of the solution were the PreRender event, the RegisterStartupScript method, and the enumeration of all ImageButton controls within the User Control.

This solution should work similarly for Page objects in addition to User Control objects, and for Image controls in addition to ImageButton controls.

Source Code

public class BaseUserControl : System.Web.UI.UserControl { public BaseUserControl() { this.ID = "BaseUserControl"; this.PreRender += new System.EventHandler(Page_PreRender); }

private void Page_PreRender(object sender, EventArgs e) { Debug.WriteLine(this.ID + ".Page_PreRender"); if (!Page.IsStartupscriptRegistered(this.ID + "_preload_images")) { string sURL, sOverURL; ImageButton ib = null; StringBuilder sb_front = new StringBuilder(); StringBuilder sb_back = new StringBuilder(); int iCount = 0;

foreach (Control c in this.Controls) { if (c is ImageButton) { ib = (ImageButton)c; sURL = ib.ImageUrl; sOverURL = ib.Attributes["oversrc"]; sb_back.Append(@"preload_images[" + iCount.ToString() + "] = new Image();"); sb_back.Append(@"preload_over_images[" + iCount.ToString() + "] = new Image();"); sb_back.Append(@"preload_images[" + iCount.ToString() + "].src = '" + sURL + "'; \n"); sb_back.Append(@"preload_over_images[" + iCount.ToString() + "].src = '" + sOverURL + "'; \n"); iCount++; } }

if (iCount > 0) { sb_back.Append(@""); string sCount = iCount.ToString(); sb_front.Append(@"