Creating a Text Box Server Control with Color Highlighting
By Grant Killian
Published: 12/29/2003
Reader Level: Intermediate
Rated: 4.50 by 6 member(s).
Tell a Friend
Rate this Article
Printable Version
Discuss in the Forums

Download the Source

Creating your own controls is a great way to leverage the .NET Framework in your applications. You can extend existing controls with your own properties and behavior, combine controls together into composite controls, and even create your own control from scratch. Furthermore, by using client-side JavaScript with our controls, we can achieve a powerful level of interactivity and sophistication without having to constantly post back to the server. In this article, I'll walk through creating a customized ASP.NET text box control that changes background color when it gains and loses focus. Our new "pimped-out" text box will include:

  • Color highlighting when users enter data into the text box (courtesy of some client-side JavaScript)
  • Logic to gracefully handle browsers that don't support our highlighting
  • Design-time support for the background color properties, in the Visual Studio .NET (VS .NET) Property window and on the Designer surface

Let's start by creating a blank VS .NET project, and then add an ASP.NET WebApplication project (I named mine WebApplication) and a Web Control Library project (I named mine ControlLib) to the solution. Rename the WebForm1.aspx file in the WebApplication to container.aspx; rename the WebCustomControl1.cs file in the Web Control Library project to PimpedOutTextbox.cs. It's always good to have meaningful names for your files! Our container.aspx page will host the custom control once we've compiled it. Our Solution Explorer should look like FIGURE 1.

FIGURE 1: The new files in Solution Explorer

Let's add some code to our PimpedOutTextbox class. Since this is a Web Control Library project, VS .NET automatically adds the "using" statements we'll need. After the using statements, replace the namespace and class definition with the following code:

line 1:    [assembly: TagPrefix ( "ControlLib" , "lib" )]
line 2:    namespace ControlLib
line 3:    {
line 4:      [DefaultProperty( "BackColorOn" ),
line 5:      ToolboxData( "<{0}:PimpedOutTextbox runat=server></{0}:PimpedOutTextbox>" )]
line 6:      public class PimpedOutTextbox : System.Web.UI.WebControls.TextBox
line 7:      {

Starting at the top, I've added an assembly attribute to the namespace that will control the TagPrefix VS .NET uses when we drag and drop our control onto a Web form. It doesn't impact our control functionality, just the way it gets generated in VS .NET (more about this later).

We decorate our PimpedOutTextbox class with some additional attributes: DefaultProperty and ToolboxData. DefaultProperty controls which control property is selected by default when your control is hosted in the designer (we will define the BackColorOn property shortly). The ToolboxData attribute works in conjunction with the [assembly: TagPrefix] attribute to dictate how our control is generated in the VS .NET HTML view. Again, I'll have more to say about these attributes later; for now, just make sure your control class includes them.

Finally, on line 6, note that our control uses the ":" character to indicate we're inheriting from the WebControls.TextBox class. Our control will extend the behavior of the text box. Among other things, this means all the properties and behavior that a regular text box has will be available in our control (unless we explicitly override them!).

The next step is to add our two additional properties to the PimpedOutTextbox control. We want the user to set a color for when the control has the focus and users are typing in it (named BackColorOn), and for when the control loses the focus (named BackColorOff):

line 1:    private Color _colOff;
line 2:    [Category( "Appearance" ), Description( "The background color when the control loses focus" )]
line 3:    public Color BackColorOff
line 4:    {
line 5:      get{return _colOff;}
line 6:      set{_colOff = value
line 7:    }

line 8:    private Color _colOn;
line 9:    [Category( "Appearance" ), Description( "The background color when the control has the focus" )]
line 10:    public Color BackColorOn
line 11:    {
line 12:      get{return _colOn; }
line 13:      set{_colOn = value;}
line 14:    }

These are just basic property statements; nothing too fancy besides the Category and Description attributes on lines 2 and 9 (these control how the property is presented in the Property window of the VS .NET designer). Note that we're using a Color data type instead of a more simple string. The Color type will allow users of our control to select colors from the VS .NET color chooser instead of having to type their own hexadecimal or string values.

Now for some good stuff. The TextBox control from which we're inheriting uses a method called AddAttributesToRender() to add additional output to the browser. We're going to override this method to insert our own code for the client-side onFocus and onBlur JavaScript events. The other thing to note about this method is that the VS .NET designer calls this method when creating the control at design time, so we can also achieve design time support for our control through this method:

line 1:    protected override void AddAttributesToRender( HtmlTextWriter writer )
line 2:    {
line 3:      base.AddAttributesToRender( writer );
line 4:      //only add the client-side javascript for design mode or IE
line 5:      if( inDesignMode() || System.Web.HttpContext.Current.Request.Browser.Type.IndexOf( "IE" ) > -1 )
line 6:      {
line 7:        writer.AddAttribute( "onFocus", "JavaScript:this.style.backgroundColor='" + ColorTranslator.ToHtml( _colOn ) + "';" );
line 8:        if( _colOff.Equals( Color.Empty ) )
line 9:        {
line 10:           _colOff = this.BackColor;
line 11:        }
line 12:      writer.AddAttribute( "onBlur", "JavaScript:this.style.backgroundColor='" + ColorTranslator.ToHtml( _colOff ) + "';" );
line 13:      }
line 14:    }

To begin, line 3 invokes the base AddAttributesToRender method in the TextBox class — this ensures our control has all the functionality of the parent TextBox object. The C# base object is how derived classes use properties and methods in a parent object. The AddAttributesToRender method uses an HtmlTextWriter as a parameter; we call the AddAttribute method on the HtmlTextWriter to add our client-side code to the output stream. Lines 7 and 12 demonstrate our use of this technique. Note that we pass two arguments to AddAttribute, the first is the Html attribute and the second is the value for the attribute (they render as Key=Value pairs in the generated HTML like this: <input type="text" onBlur="JavaScript...">).

We're just building dynamic text to include with the HTML generated for our control. Since Web browsers use a hexadecimal color (and some literal colors such as Lime or Blue), we use the ColorTranslator class to convert our .NET Color type to a Web browser equivalent (lines 7 and 12 ). The ColorTranslator class is a good one with which to familiarize yourself. On line 8, we test to see if the _colOff property is not set (Color.Empty) and assign the regular BackColor value to our _colOff variable. This has the subtle effect of setting the BackColorOff property to the same color as the BackColor property — a nice touch for the control user.

Note that we're detecting the browser type on line 5. Internet Explorer (IE) supports our dynamic onFocus and OnBlur event handling, but Netscape and others might balk at the JavaScript. To avoid nasty JavaScript errors, we only apply our extra code for IE browsers. Of course, you could conditionally branch based on any browser type and include any browser specific code you need — in the interest of brevity, this example doesn't take things that far.

We also want our color highlighting code to be included when in VS .NET design mode, thus our boolean inDesignMode function:

line 1:     private bool inDesignMode()
line 2:     {
line 3:       bool blnOut = false;
line 4:       if( object.ReferenceEquals( System.Web.HttpContext.Current, null ) )
line 5:       {
line 6:         blnOut = true;
line 7:       }
line 8:       else
line 9:       {
line 10:         blnOut = false;
line 11:        }
line 12:       return blnOut;
line 13:     }

Line 4 is where the real action is here. If there isn't an HttpContext for us to work with, we can assume our control is in design mode and not being served up over HTTP. If we didn't put this check in, our controls wouldn't display as text boxes in the designer.

That's the tour of our PimpedOutTextbox. We should build our Web control library project and move into the WebApplication project to take our control for a test drive.

Testing the New Control

Before we can use the custom control in our project, we need to reference it in our WebApplication. Right-click on References in the WebApplication and select Add Reference. On the Projects tab, select the Web Control library and click OK; this copies the assembly, the dll, with our control in it into the bin directory of the WebApplication. To add the control to the Toolbox, right-click on the Toolbox and select Add/Remove Items, as shown in FIGURE 2.

FIGURE 2: Adding our custom control to the Toolbox

Make sure you're on the .NET Framework Components tab and click the Browse button to locate the assembly in the WebApplication's bin directory. The PimpedOutTextbox control should automatically become selected in the Customize Toolbox window. Click OK. The PimpedOutTextbox is now available for us to click and drag onto our Web form (look for PimpedOutTextbox at the bottom of your Toolbox control list).

Go ahead and add a PimpedOutTextbox to the Web form. Notice the Property page in the designer automatically selects our BackColorOn property (this is due to our [DefaultProperty()] attribute in the control class). Also note the Description in the bottom of the Property page — courtesy of our [Description] attribute. Furthermore, if you switch to HTML view, you'll see the impact of our TagPrefix and ToolboxData attributes. The Register Page Directive reflects our assembly attribute, as does the text defining the custom control.

Back in design view, set the BackColor of the PimpedOutTextbox to gray and notice that the BackColorOff property gets assigned the same value (this only happens if BackColorOff doesn't already have a value). Switch it back to white and notice that BackColorOff doesn't change — this is due to the this.BackColorOff.Equals( Color.Empty ) logic we added in our overridden AddAttributesToRender(). Next, set the BackColorOn property to any color other than white and run your WebApplication to see the PimpedOutTextbox in action. When the control has the focus, the background of the text box is highlighted. When the focus leaves the control (firing the client-side onBlur event in the browser), the background is set to the BackColorOff property, as shown in FIGURE 3.

FIGURE 3: The WebApplication in action

You can try it with a non-IE browser and confirm that our conditional logic is working — meaning there are no JavaScript errors (and no color highlighting). We can go further and set a breakpoint in our AddAttributesToRender method and step through the execution of our logic when a page loads on the server; this is vital to sophisticated control debugging.

If you want to step through the client-side code, you can debug your JavaScript code using VS .NET. Make sure Internet Explorer doesn't have client-side debugging disabled. Then, add a debugger; statement to where you want your JavaScript breakpoint to hit, like this:

    JavaScript:debugger;this.style.backgroundColor='blue';

Run your application and try it out. The debugger; statement acts like a client-side breakpoint. You'll be able to interrogate variables and the document object model from the VS .NET immediate window. Try it and type document.forms[0].all[1].name in the immediate window. You'll get the name of the first control on the page (it's a zero-based array, but the control at ordinal position zero is used for the hidden __VIEWSTATE control). The more complicated the JavaScript, the more useful this technique becomes.

I've only scratched the surface of control development and client-side script; we could make the forecolor change or make the font-style become bold when the text box has the focus or wrap our control in a span tag and assign a color to the span for different events in the control's lifecycle. By unlocking the door to client-side script in our ASP.NET controls, the possibilities are endless. This PimpedOutTextbox is not "big pimpin'" — it's just "lil' pimpin'!" I'll leave the other properties and extension points for you to implement. Just be sure to not overwhelm the user — a little bit of JavaScript like this goes a long way.

Marketplace
(Sponsored Links)
What are the green links?
   



 
Copyright © 2007 CMP Tech LLC |
Privacy Policy (4/10/06) | Your California Privacy Rights (4/10/06) | Terms of Service | Advertising Info | About Us | Help