There is a cool new feature in ASP.NET 2.0 that allows you to embed resources into your server side assemblies and have your web controls request these resources automatically. This is especially handy when you want to deploy a new control. No longer do you have to find just the right spot to place the JavaScript and image files that your control depends on. Microsoft already uses this technique with its validators. The JavaScript needed for client side validation is embedded in one of the .NET assemblies on the server. If you were to view the source of any web page that uses a validator in ASP.NET 2.0, you might see something like this: <script src="/MyWebSite/WebResource.axd?d=68d8KT0ikvX6J4c8Z8zwvfZXzPdyyYYY8TuccizWlCePFWz&t=632847500868593750" type="text/javascript"></script>
This is a request to a new HttpHandler, WebResources.axd, for the necessary JavaScript. The first parameter, ‘d’ is an encrypted identifier telling the handler which resource it needs. The ‘t’ parameter is an encrypted timestamp, used to determine if the resource has changed.
Looks pretty simple right?
Well, lets see how easy it is for you to use this technique. Lets try to create a control that has its JavaScript embedded as a resource. For this example, I am going to use a useful script that buffers key presses and matches an entire word in a dropdownlist instead of just the first character. (Thanks to Jonathan Cogley at ASP Alliance for the original script: http://authors.aspalliance.com/thycotic/articles/view.aspx?id=3)
First, lets open up or create a new web site in Visual Studio 2005 and then add a new Web Control Library project to it. After adding the project, remember to add a reference to it from our web site. This new assembly will contain all of the elements of our control and our web site has to know about it to use it.
Next, lets add a new class that inherits from DropDownList:
using System;using System.Collections.Generic;using System.Text;using System.Web.UI.WebControls;using System.Web.UI; namespace WebControlLibrary1{ public class KeyedDropDownList : DropDownList { private bool _caseSensitive = false; public KeyedDropDownList(){} public bool CaseSensitive { get { return _caseSensitive; } set { _caseSensitive = value; } } }}
I have also added a property “CaseSensitive” which will be passed to the script to allow us to turn on and off case sensitivity when matching strings in our list.
Now add a new a JScript file and examine the properties. To embed this file as a resource the Build Action must be set to 'Embedded Resource'. After setting the build action, feel free to copy this code into the file or substitute JavaScript of your own:
function KeyedDropDownList_onkeypress(dropdownlist,caseSensitive) { // check the keypressBuffer attribute is defined on the dropdownlist var undefined; if (dropdownlist.keypressBuffer == undefined) { dropdownlist.keypressBuffer = ''; } // get the key that was pressed var key = String.fromCharCode(window.event.keyCode); dropdownlist.keypressBuffer += key; if (!caseSensitive) { // convert buffer to lowercase dropdownlist.keypressBuffer = dropdownlist.keypressBuffer.toLowerCase(); } // find if it is the start of any of the options var optionsLength = dropdownlist.options.length; for (var n=0; n < optionsLength; n++) { var optionText = dropdownlist.options[n].text; if (!caseSensitive) { optionText = optionText.toLowerCase(); } if (optionText.indexOf(dropdownlist.keypressBuffer,0) == 0) { dropdownlist.selectedIndex = n; return false; // cancel the default behavior since // we have selected our own value } } // reset initial key to be inline with default behavior dropdownlist.keypressBuffer = key; return true; // give default behavior}
Next, you must add an attribute to the assemblyinfo.cs file to reference the embedded resource:
[assembly: System.Web.UI.WebResource("WebControlLibrary1.JScript1.js", "text/javascript")]
Now, instead of registering the script block with the necessary JavaScript ourselves, we will register a request to get the script block from our assembly. Thanks to the new ClientScriptManager in ASP.NET 2.0, this is very easy. We will first override the OnInit method of our KeyedDropDownList class and then get a reference to this manager to do most of our work.
protected override void OnInit(EventArgs e) { base.OnInit(e); ClientScriptManager cs = Page.ClientScript; Type rsType = this.GetType(); cs.RegisterClientScriptInclude("MyScript", cs.GetWebResourceUrl(rsType,"WebControlLibrary1.JScript1.js"));}
The last piece of coding is very simple. Just attach the onkeypress event of our control to our custom JavaScript function. Although in this example we have not used the ViewState to track our lone property, we might want to do that or add more properties that can be passed to the JavaScript function. So here I overrode the OnLoad method to add the attribute to our webcontrol. By the time the OnLoad event is fired, the ViewState will have been loaded.
protected override void OnLoad(EventArgs e){ base.OnLoad(e); this.Attributes.Add("onkeypress", "return KeyedDropDownList_onkeypress(this," + _caseSensitive.ToString().ToLower() + ")");}
If all goes well, we should be able to now use this control on any form in our web app and the necessary JavaScript will automatically accompany it wherever it goes. I should also point out that when debugging, the JavaScript is not cached, it is downloaded each time. When debugging is off, the JavaScript is cached on the client automatically. I have included the markup for the test page that registers and uses this new control below.
<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %><%@ Register Assembly="WebControlLibrary1" Namespace="WebControlLibrary1" TagPrefix="wcl" %><html xmlns="http://www.w3.org/1999/xhtml"><head id="Head1" runat="server"> <title>Test Page</title></head><body> <form id="form1" runat="server"> <wcl:KeyedDropDownList id="ddlTest" runat="server"> <asp:ListItem Value="1">Calendar</asp:ListItem> <asp:ListItem Value="2">Can</asp:ListItem> <asp:ListItem Value="3">Candle</asp:ListItem> <asp:ListItem Value="4">Canary</asp:ListItem> <asp:ListItem Value="5">Card</asp:ListItem> <asp:ListItem Value="6">Cat</asp:ListItem> <asp:ListItem Value="7">Cow</asp:ListItem> </wcl:KeyedDropDownList> </form></body></html>
Remember Me
a@href@title, i, strike, u
Copyright © 2003-2008 Falafel Software Inc.
Subscribe to Falafel Blogs
The opinions expressed herein are Falafel's employees own personal opinions and do not represent Falafel Software's view in any way in case they go bananas!