Beautiful Buttons Abound

Create Attractive Buttons with the NiftyButton Control

ControlFreak

LANGUAGES: C# | VB.NET

ASP.NET VERSIONS: 1.x

 

Beautiful Buttons Abound

Create Attractive Buttons with the NiftyButton Control

 

By Steve C. Orr

 

The standard Web button control is boring, pedestrian, and ugly. That s why few attractive Web sites use them. Instead, most use images. The drawback is that it takes a significant amount of time to create enough images to fill all the image buttons of an entire Web site. It also takes time to manage them and redo them all the next time the design of the site changes. Wouldn t it be nice to have a better button control that could radically change its own appearance just by setting a few properties? Well now you ll have one.

 

The NiftyButton control we ll create in this article can be used to create strikingly attractive buttons that can be created and configured dynamically, with no images required. This control builds on my DirectX column Eye Candy by utilizing filters to do the heavy lifting.

 

To create such a control, you might first envision a control that generates its own images by using the System.Drawing namespace; for more on the use of the System.Drawing namespace, see Improve Your Image(s). This could potentially save some image management effort and create attractive results. However, Internet Explorer dictates that images must ultimately be generated via their own URL, which means that any kind of image button must rely on code that doesn t exist in the current page. Therefore, you must have another page to generate the image or an HTTP handler to intercept such requests and do the work. This makes deployment and configuration a hassle. Wouldn t it be better to have a button control that can change its appearance without relying on images? Well, now you ll have one.

 


Figure 1: This button was created entirely with HTML. No images were required. The results look great in Internet Explorer, and the special effects are ignored by other browsers (which end up displaying fairly standard looking buttons).

 

If you recall from Eye Candy, filters can be applied to standard buttons to improve their look. The following snippet transforms an ugly gray square button into the fuzzy blue oval button shown in Figure 1:

 

value="Oval Shaped" id="NiftyButton10" style="FILTER:

progid:DXImageTransform.Microsoft.Alpha(style=2,startX=0,

startY=0,finishX=100,finishY=100,opacity=100,

finishOpacity=0);

COLOR:deepskyblue;BACKGROUND-COLOR:darkblue">

 

The Alpha filter defined inside the style for this button accepts up to seven parameters. In addition, you can combine multiple filters for a seemingly infinite number of effects. You ve probably noticed this HTML definition is rather nonstandard looking. It s an odd way to define parameters and the resulting HTML can get quite complex when combining multiple filters. It can also end up being quite a maintenance chore to keep all of these complicated definitions consistent across a large Web site. As if that weren t enough complexity, Internet Explorer is very picky about line breaks and spaces in filter definitions, and Visual Studio 2003 will happily (and often) reformat the HTML so that it changes just enough to break the code, but not enough to make the cause of the problem obvious. Wouldn t it be nice to have a button control that encapsulated all this complexity by exposing valid filter options and parameters through a few well designed properties?

 

A Nifty Button Control

Like all custom controls, the NiftyButton control is a DLL that you can add to your Visual Studio toolbox (by right clicking on the toolbox, choosing Add/Remove Items and browsing to the DLL). Then you can drag the control onto any Web form and set its properties to change how it will look at run time.

 

Using the NiftyButton control, a button identical to that shown in Figure 1 can be created with the following definition:

 

Text="Oval Shaped" BackColor="DarkBlue" Alpha-Visible="True"

Alpha-StartX="0" Alpha-StartY="0" Alpha-Style="Radial"

Alpha-FinishOpacity="0" Alpha-FinishY="100"

Alpha-FinishX="100" Alpha-Opacity="100"

ForeColor="DeepSkyBlue">

 

This HTML snippet looks much cleaner and more intuitive than the previous example. Of course, you need not muck with such definitions at all because the designer and properties window in Visual Studio can manage all of this for you.

 

The NiftyButton control inherits from the standard button Web control, so it gets all of that functionality automatically. The NiftyButton control adds properties to manage parameters for the nine different filters that it supports. It then concatenates the required style strings and outputs them via the OnPreRender event listed in Figure 2.

 

protected override void OnPreRender(EventArgs e)

{

 //remove the old filter string (if any)

 this.Style.Remove("filter");

 

 //Build the new filter style string

 StringBuilder sb = new StringBuilder();

 if (this.FlipHorizontal) sb.Append("fliph ");

 if (this.FlipVertical) sb.Append("flipv ");

 if (this.XRay) sb.Append("xray ");

 

 // delegate the subclasses to add their

 // own filter style strings

 sb.Append(_Alpha.GetStyle());

 sb.Append(_Blur.GetStyle());

 sb.Append(_DropShadow.GetStyle());

 sb.Append(_Emboss.GetStyle());

 sb.Append(_Engrave.GetStyle());

 sb.Append(_Glow.GetStyle());

 

 //Output the completed style string to the control

 if (sb.Length>0) this.Style.Add("filter",

   System.Environment.NewLine + sb.ToString());

}

Figure 2: The OnPreRender event of the NiftyButton is where the majority of the control s functionality is orchestrated.

 

First, any preexisting filters (that may have been placed there on a previous postback) are removed so that the current settings will be rendered instead.

 

In the second code block, a few of the more simple (paramaterless) filters are generated and added to the StringBuilder buffer. The third code block calls the GetStyle method implemented in the subclasses that represent the more complex filters. Each of these subclasses will generate their own output and add it to the StringBuilder buffer. These subclasses will be examined in more detail later in this article.

 

The final line in Figure 2 flushes the StringBuilder buffer into the page by adding the resulting string to the Style collection of the control.

 

X-Ray Vision

XRay is a simple filter that takes no parameters. When enabled, it averages the red and green values to create a grayscale output that can look rather alluring, especially when combined with other filters. This filter is exposed through a simple Boolean property of the NiftyButton control:

 

[Bindable(true), Category("Filter"),

Description("Grayscale, averages red & green values.")]

public bool XRay

{

 get

 {

   return((ViewState["xray"] == null) ? false :

      (bool)ViewState["xray"]);

 }

 set {ViewState["xray"] = value;}

}

 

The property has three attributes. The first attribute (Bindable) permits data binding. The second attribute (Category) ensures this property will appear under the Filter category of the properties window when the control is compiled and placed on a Web form. The third attribute (Description) will appear in the bottom portion of the properties window when the property is selected. The get and set methods use ViewState to store the property value so it will be persisted between page postbacks. If no value is found in ViewState, the default of False will be used, which will turn off the XRay effect. The NiftyButton control contains several other similar properties that can be examined by downloading the source code (see end of article for details). See Figure 3 for a partial list of filters managed by the NiftyButton control.

 

Filter

Description

Example Syntax

Alpha

Adjusts the opacity of the object.

progid:DXImageTransform.Microsoft.Alpha(style=2, startX=0, startY=0, finishX=100, finishY=100, opacity=100, finishOpacity=0)

DropShadow

Creates a solid silhouette of the object, offset in the specified direction.

progid:DXImageTransform.Microsoft.DropShadow(color=red, offX=2, offY=2, positive=true)

Emboss

Displays the object as embossed texture with grayscale.

progid:DXImageTransform.Microsoft.Emboss(Bias=50)

Engrave

Displays the object as engraved texture with grayscale.

progid:DXImageTransform.Microsoft.Engrave(Bias=50)

Glow

Adds radiance around the edges of the object.

progid:DXImageTransform.Microsoft.Glow(color=red, strength=6)

MotionBlur

Causes the object to appear to be in motion.

progid:DXImageTransform.Microsoft.MotionBlur(add=true, direction=180, strength=6)

Figure 3: These are a few of Microsoft s many DirectX filters that are exposed for Web page elements to consume. These filters (and others) are managed automatically by the NiftyButton control so you needn t be worried about the somewhat arcane syntax.

 

A Glowing Review

The Glow filter is more complex than the XRay filter. The Glow filter accepts several parameters, which are exposed via NiftyButton properties. The Glow property is read-only, and is publicly exposed with the following code:

 

[DesignerSerializationVisibility

        (DesignerSerializationVisibility.Content),

NotifyParentProperty(true), Category("Filter")]

public glow Glow

{

 get{return _Glow;}

}

 

The get method simply returns an instance of the Glow class, which is encapsulated within the NiftyButton class. More interesting in this code snippet, however, are the attributes. As mentioned previously, the Category attribute specifies that this property will show up in the Filter section of the property window. The other two attributes ensure that this subclass will persist its properties. The NotifyParentProperty attribute ensures that any changes to the properties in this subclass will bubble up to the containing NiftyButton object so that they will manage state in unison. The DesignerSerializationVisibility attribute ensures that changes made in the properties window of Visual Studio will be persisted to the HTML definition in the ASPX page.

 

The source code for the Glow class is shown in Listing One. The Glow class is a subclass of the NiftyButton control. It encapsulates the complexities involved with managing and displaying the Glow filter. The class is defined using the TypeConverter attribute, which is given the ExpandableObjectConverter as a parameter. This ensures that the properties of this class will appear in the properties window in an expandable way. That is, a + sign will appear next to the property to let it expand and show all its properties at design time, as shown in Figure 4.

 


Figure 4: The ExpandableObjectConverter TypeConverter attribute allows subclasses to be expanded to show their properties. In this example, the Glow class has been expanded (via the plus signs along the left) to show its three properties: Color, Strength, and Visible.

 

The constructor of the Glow class shown in Listing One accepts a StateBag as a parameter, so it can accept ViewState as a parameter from the containing NiftyButton control. The Visible property (which is False by default) uses ViewState to retain its value between page postbacks. The Color property is similar, with a default value of Red. The Strength property adds some basic bounds checking to ensure the value is not zero.

 

The ToString property is overridden so a value can be displayed directly next to the Glow property in the properties window (as illustrated in Figure 4). In this case, it merely displays Visible or Not Visible , but it could easily display a more complex representation of the data contained within the object.

 

The final piece of code in the Glow class is the GetStyle function. It concatenates the Glow filter s Style string together according to the property values. It inserts spaces and new line characters where necessary to ensure proper display in the browser.

 

The Glow class is one of many subclasses in the NiftyButton control. The rest of the subclasses have the same basic design and can be downloaded for a detailed review.

 

More Niftiness?

Standard buttons are boring, Image buttons are a maintenance hassle, and filters (by themselves) use an overly complicated syntax. I hope you agree that the NiftyButton control is a nifty solution for all these problems (see Figure 5).

 


Figure 5: The NiftyButton control can display in a nearly infinite number of ways by simply adjusting some properties.

 

After examining the NiftyButton source code you should have a good understanding of how to build custom controls, inherit and extend existing Web controls, and use filters to visually enhance controls. You should also have a good feel for creating controls that provide a quality design-time experience by using attributes to expose complex public property trees.

 

Give the NiftyButton a whirl and let me know what you think of it. Feel free to tinker with the code, expand upon it, and learn from it. Drop me an e-mail if you come across any interesting new revelations on the subject; I d love to hear about them.

 

References

Filter References

http://www.w3schools.com/dhtml/dhtml_css.asp

http://msdn.microsoft.com/workshop/author/filter/reference/reference.asp

 

ExpandableObjectConverter

http://www.bluevisionsoftware.com/WebSite/TipsAndTricksDetails.aspx?Name=ExpandableObjectConverter

 

The sample code in this article is available for download.

 

Steve C. Orr is an MCSD and a Microsoft MVP in ASP.NET. He s been developing software solutions for leading companies in the Seattle area for more than a decade. When he s not busy designing software systems or writing about them, he can often be found loitering at local user groups and habitually lurking in the ASP.NET newsgroup. Find out more about him at http://SteveOrr.net or e-mail him at mailto:[email protected].

 

Begin Listing One

[TypeConverter(typeof(ExpandableObjectConverter))

Description("Adds radiance around the button edges.")]

public class glow {

 

private StateBag _ViewState;

public glow(StateBag ViewState) //Constructor

{

 _ViewState=ViewState;

}

 

[NotifyParentProperty(true),

Description("Should the glow be visible at runtime?")]

public bool Visible

{

 get

 {

   return((_ViewState["glowVisible"] == null) ? false :

      (bool)_ViewState["glowVisible"]);      

       }

 set {_ViewState["glowVisible"] = value;}

}

 

[NotifyParentProperty(true),

Description("The color of the glow around the button.")]

public Color Color

{

 get

 {

   return((_ViewState["GlowColor"] == null) ? Color.Red :

      (Color)_ViewState["GlowColor"]);     

       }

 set

 {_ViewState["GlowColor"] = value;}

}

 

[NotifyParentProperty(true),

Description("Number of pixels that the effect extends.")]

public byte Strength

{

 get

 {

   return((_ViewState["GlowStrength"] == null) ? (byte)6 :

      (byte)_ViewState["GlowStrength"]);

       }

 set 

 {

   if (value<1) value=1;

   _ViewState["GlowStrength"] = value;

 }

}

 

public override string ToString()

{

 //For appearances in the property window

 if (this.Visible) return "Visible" ;

       else return "Not Visible";

}

 

 public String GetStyle()

 {

 StringBuilder sb = new StringBuilder();

 if (this.Visible)

 {

   sb.Append(" progid:DXImageTransform.Microsoft.Glow(");

   sb.Append("color="+ this.Color.ToKnownColor() + ",");

   sb.Append("strength="+ this.Strength.ToString() + ") ");

   sb.Append(System.Environment.NewLine);

   return sb.ToString();

 }

 else

 {

   return string.Empty;

 }

 }

}

End Listing One

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish