I have been away for a while, enjoying some of the theater in the London West End. I learned quite a few things on the trip. First, as a visit to the Duke of York's Theater proved, sitting and listening to Jeremy Irons (in Embers) is an extremely good use of your time. Second, as a visit to the Old Vic theater proved, if you see Kevin Spacey speaking with a distinguished looking gentleman at the end of your row (at Resurrection Blues), and you ask a bit too loudly what Robert Altman looks like, he will respond, "he looks like me."
To get back into the swing of things, I have decided to veer away a bit from some of the more theoretical discussions and delve into some practical issues of creating great looking applications. There is a lot of excitement out there around some of the interesting new technologies looming on the horizon. Windows Presentation Foundation (formerly Avalon) provides you with a sack full of goodies for creating some extremely compelling user interfaces. However, that doesn't mean that you can't use the tools available today to create some compelling visualizations right away! One frequently overlooked gem is the technology already available with Windows Forms, which provides you with a very robust platform for creating fantastic visualizations.
To begin this exploration, I have selected the ever popular Gel Buttons. Valentin Iliescu, a Visual C# MVP, recently posted a blog entry on how to create Gel Buttons using WPF and the Expression Interactive Designer. We can do the same thing with Windows Forms.
Windows Forms Gel Buttons : First Revision
If we look at the overall problem, what we want to create is fairly straightforward. the bottom layer of the button is a smooth gradient, from some starting color to some ending color. Next, we layer on top of that a gradient starting with completely opaque white and ending with completely transparent white, which creates the highlight. Finally, we can draw the text. Since we are looking to implement all of the behaviors of a button, and modify only the appearance, we can inherit from Button and override the drawing behavior. We will want to add a couple of additional properties to allow our users to customize the gradient colors. For this first installment, that's all that we have to do! Let's take a look at the code to implement this.
namespace GelButtons {
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
class GelButton : Button {
Color gradientTop = Color.FromArgb(255, 44, 85, 177);
Color gradientBottom = Color.FromArgb(255, 153, 198, 241);
[Category("Appearance"), Description("The color to use for the top portion of the gradient fill of the component.")]
public Color GradientTop {
get {
return this.gradientTop;
}
set {
this.gradientTop = value;
this.Invalidate();
[Category("Appearance"), Description("The color to use for the bottom portion of the gradient fill of the component.")]
public Color GradientBottom {
return this.gradientBottom;
this.gradientBottom = value;
protected override void OnPaint(PaintEventArgs pevent) {
Graphics g = pevent.Graphics;
// Fill the background
using (SolidBrush backgroundBrush = new SolidBrush(this.BackColor)) {
g.FillRectangle(backgroundBrush, this.ClientRectangle);
// Paint the outer rounded rectangle
g.SmoothingMode = SmoothingMode.AntiAlias;
Rectangle outerRect = new Rectangle(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width - 1, ClientRectangle.Height - 1);
using (GraphicsPath outerPath = RoundedRectangle(outerRect, 5, 0)) {
using (LinearGradientBrush outerBrush = new LinearGradientBrush(outerRect, gradientTop, gradientBottom, LinearGradientMode.Vertical)) {
g.FillPath(outerBrush, outerPath);
using (Pen outlinePen = new Pen(gradientTop)) {
g.DrawPath(outlinePen, outerPath);
// Paint the highlight rounded rectangle
Rectangle innerRect = new Rectangle(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width - 1, ClientRectangle.Height / 2 - 1);
using (GraphicsPath innerPath = RoundedRectangle(innerRect, 5, 2)) {
using (LinearGradientBrush innerBrush = new LinearGradientBrush(innerRect, Color.FromArgb(255, Color.White), Color.FromArgb(0, Color.White), LinearGradientMode.Vertical)) {
g.FillPath(innerBrush, innerPath);
// Paint the text
TextRenderer.DrawText(g, this.Text, this.Font, outerRect, this.ForeColor, Color.Transparent, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis);
private GraphicsPath RoundedRectangle(Rectangle boundingRect, int cornerRadius, int margin) {
GraphicsPath roundedRect = new GraphicsPath();
roundedRect.AddArc(boundingRect.X + margin, boundingRect.Y + margin, cornerRadius * 2, cornerRadius * 2, 180, 90);
roundedRect.AddArc(boundingRect.X + boundingRect.Width - margin - cornerRadius * 2, boundingRect.Y + margin, cornerRadius * 2, cornerRadius * 2, 270, 90);
roundedRect.AddArc(boundingRect.X + boundingRect.Width - margin - cornerRadius * 2, boundingRect.Y + boundingRect.Height - margin - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 0, 90);
roundedRect.AddArc(boundingRect.X + margin, boundingRect.Y + boundingRect.Height - margin - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 90, 90);
roundedRect.CloseFigure();
return roundedRect;
Now that we have explored the fact that we can create a gel button, we should consider when we should create a gel button. Common controls exist for a reason - they provide a consistent user interface, allowing every application to feel familiar to the user. When you rely on common controls, particularly when you style these controls using visual styles, you get some degree of assurance that your controls will be updated with subsequent versions of the operating system, and that they will change when the user changes the visual style they are using to look consistent with other screen elements.
However, not all applications necessarily want to play by these rules. Consider Windows Media Player - the buttons here are not just simple button controls, but they are highly stylized controls that are appropriate to the overall feel of the application. If you are developing something that is more consumer targeted, or that has a specific UI theme around which you are building the entire user experience, then perhaps you don't want to be limited to what the operating system provides. Doing some custom painting is fairly straightforward, and gives you the ability to finely craft your presentation to suit the experience you are hoping to deliver.
Thinking about custom painting, things become even more interesting when you consider creating a type of control that the operating system does not provide. It is probably better to implement a control specifically targeted to support your application than to bend the user experience to fit into the constraints of the common controls that are already provided. We will delve a bit into this in later episodes.
Having considered that, let's consider how complete we feel this implementation is. Here, we are rendering a static image. Depending on your aesthetic tastes, you may feel that these look nice, but in essence they are nothing but static images. We could achieve static images using an image control alone, so why spend the time custom drawing it? After all, it is faster just to move memory around than it is to perform computations in order to complete our rendering. This is where Windows Forms really hits its sweet spot - having complete control over the video card gives you limitless possibilities for rich interaction. We don't need to stop at rendering a picture and calling it a button (which is very frequent on the web). Rather, we would like our button to be pliant. We don't want it to just look like a button, we would like it to behave like a button. We want it to announce clearly that it is clickable. When we move the mouse over the button, we would like it to tell us that we have moved over an object that will respond to us. When we push the button, we would like for it to look pushed. So, in our next episode, let's do exactly that - let's harness the capabilities that Windows Forms provides to make a gel button that actually behaves like a button, rather than just using our code to draw an interesting looking picture.
Genetic Algorithms allow for a rapid exploration of a problem domain. This exploration is automated and intentionally random. What happens if you are exploring a problem domain programmatically? You want to allow yourself room to explore this problem domain with the greatest efficiency.
To explore this, let's start with a simple case: converting a string to the upper case representation of that string.
Results of Low-Tech ToUpper Function
If you think about this while looking at an ASCII table, you may very well notice that all lower case characters are sequential and have ASCII codes between 97 and 122. Concomitantly, all upper case characters are sequential and have ASCII codes between 65 and 90. It doesn't require much mathematical acumen to determine that you can check the ASCII value, and if it is between 97 and 122, subtract 32. The more mathematically astute will notice that 32 is a power of two, and thus the computation could be computed using a logical and. Thus, we could create a solution that uses very few assembly language instructions. A very simple implementation would be:
.code
mov ecx, LENGTHOF array
mov esi, OFFSET array
L1:
and BYTE PTR [esi], 11011111b
inc esi
loop L1
Obviously, it's not terribly likely that anyone today would be implementing much using assembly language, but this solution maps easily into higher level languages. If you take a look at how this is done in C, you can find the following macros (which uses the subtraction method rather than the logical and method) in ctype.h:
#define __ascii_toupper(c) ( (((c) >= 'a') && ((c) <= 'z')) ? ((c) - 'a' + 'A') : (c) )
#define _toupper(_Char) ( (_Char)-'a'+'A' )
So, it seems that we have the problem solved, and we can simply call a macro or a function to have our text converted to uppercase.
Except...
This solution only really works on English text. What if I am localizing to Greek? A lower case alpha is unicode character number 945, while an upper case alpha is 913. Oops. Now, I am not converting this character to its upper case equivalent. The characters are still 32 bits apart, so I could still use a similar technique, but now I have to add a series of ranges - I can't just use 97 to 122. How do I figure that out? Perhaps I remember the upper and lower case Greek letters from math class, but what about other alphabets? Can I be certain that I am correctly implementing it for every language that Unicode supports?
A good approach is to abstract away the problem, and implement what you know you are supporting. If you don't yet have a version of your application localized to Cyrillic, then you don't necessarily have to implement this method for that today, but you would like to be able to implement the ToUpper function once you have localized the rest of the application without having to scour your code ripping and replacing to add this functionality in.
The .NET Framework implements the ToUpper function very much like this. The ToUpper method of System.String passes the call to the CultureInfo object (which will either be the current culture or the culture you specify). If you add support for additional locales, you can just add additional CultureInfo objects, without modifying the code that already exists. This allows localization to evolve naturally without touching the rest of the code.
One real world example that I worked with recently was with the notion of authentication and authorization. I have seen many applications where authentication logic was hard wired into the web page. The same is true of authorization. This makes it difficult to change authentication and authorization if (or, more likely, when) you get to a level of complexity where identity management becomes a key initiative. If you bake in authentication throughout your database, then what happens if you begin using a dedicated, global authentication store, such as Active Directory or ADAM? If you hard code in authorization, then what happens if you move to a dedicated, global authorization store, such as Windows Authorization Manager? If you bake all of this functionality into your web pages, then what happens when you want to begin exposing some of that functionality through web services? This is one area where things are likely to evolve - therefore, it makes sense to architect your solution to support this natural evolution, rather than having the evolution cause you more work later on.