Click here to Skip to main content
6,595,854 members and growing! (19,480 online)
Email Password   helpLost your password?
Desktop Development » Button Controls » General     Intermediate License: The Code Project Open License (CPOL)

Yet Another Vista-Style CommandLink

By VCSKicks

An OS-independent CommandLink control.
C#, Windows, .NET, GDI+, Dev
Posted:17 Jul 2008
Views:33,192
Bookmarked:79 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
31 votes for this article.
Popularity: 6.83 Rating: 4.58 out of 5
2 votes, 6.5%
1

2

3
6 votes, 19.4%
4
23 votes, 74.2%
5

Introduction

There are a lot of great Vista-style controls written in .NET. So this is yet one more, a command-link button. I am a fan of creating custom controls from scratch rather than depending on the OS drawing libraries. Thus, our CommandLink is drawn entirely with C# code, making it compatible with older versions of Windows.

Goal of the CommandLink

When I set out to write the control, I decided I wanted a CommandLink that had that Vista-style feel to it, but that did replicate default Command-Links exactly. So, I wrote a simple goal list of which elements to include:

  • Two different font-sizes within the same button, i.e., for the header text and the description text.
  • An image/icon off to the left that, unlike Vista’s CommandLink, can be aligned vertically to the top, middle, or bottom.
  • A blended flat-look for default and a gradient look for the mouse-hover.
  • Behave like a button.

Rounded Rectangles

Before drawing the actual control, first, we need a function to draw rounded rectangles. Since the button will need to outline and fill the round rectangle, it is easiest to write a function that returns a GraphicsPath:

private static GraphicsPath RoundedRect(int width, int  height, int radius)
{
      RectangleF  baseRect = new RectangleF(0, 0, width, height);
      float diameter =  radius * 2.0f;
      SizeF sizeF = new SizeF(diameter,  diameter);
      RectangleF arc = new  RectangleF(baseRect.Location, sizeF);
      GraphicsPath path  = new GraphicsPath();

      // top left arc
      path.AddArc(arc,  180, 90);
      // top right arc 
      arc.X =  baseRect.Right - diameter;
      path.AddArc(arc,  270, 90);
      // bottom right  arc 
      arc.Y =  baseRect.Bottom - diameter;
      path.AddArc(arc,  0, 90);
      // bottom left arc
      arc.X =  baseRect.Left;
      path.AddArc(arc,  90, 90);

      path.CloseFigure();
      return path;
}

Drawing Elements

So, let’s break down the visual elements of the CommandLink. The only two complicated states are the Hover and the Down state.

Hover

hover-1.png

The part that makes the button pop-up is a simple white gradient that goes three-fourths of the way down the button’s height. Due to the way the LinearGradientBrush works, sometimes if the gradient drawing area is 1 pixel too tall, the gradient will start over, making an ugly white line appear in the middle of the control. To fix that, we add the following line after the LinearGradientBrush is declared:

WrapMode.TileFlipX

hover-2.png

Next comes the outline. It is a 3 radius rounded rectangle generated with the above function. The color can either be SystemColors.ColorDark, or if you prefer a fixed color, (189, 189, 189) is nice.

hover-3.png

Then, we need an inside outline. This will be 2 radius instead, and is positioned at coordinates (1, 1). The color is a slightly transparent white with an alpha value of 245.

We put it together by drawing them in order, and we get something like this:

hover-all.png

Down

down-1.png

The background this time is solid, and once again, can either be a system color (ControlLight), or (234, 234, 234), if you like fixed colors better.

down-2.png

The outline will be the same as before, except the color will be darker, (167, 167, 167).

down-3.png

Lastly, the inner outline too will only change colors to a dark color (to give a shadow effect).

The final down state:

down-all.png

Highlight

The user should be able to tell when the CommandLink is selected, even if it was done with Tab. To highlight a selected CommandLink, we draw only an inner outline with the color (192, 233, 243), which is a light blue.

Foreground – Image and Text

The foreground elements will be the same for any state of the button. There is actually nothing special to drawing the text and the image. The description text will always be three sizes smaller than the header text. The font can be changed, but the default one is Tahoma. To center the combined sizes of the header and the description text, go with:

SizeF headerLayout = g.MeasureString(headerText, this.Font);
SizeF descriptLayout = g.MeasureString(descriptionText,  descriptFont);

//Merge the two sizes into one big rectangle
Rectangle totalRect = new Rectangle(0, 0, 
                                   (int)Math.Max(headerLayout.Width,  
                                   descriptLayout.Width), 
                                   (int)(headerLayout.Height + 
                                    descriptLayout.Height) - 4);

Also, this is the part of the control that will change if the control is disabled. The text need only change color. The image, however, needs to be converted to grayscale if it hasn’t been done already.

Events to Override

There are a few events that need to be overridden to get the CommandLink to behave like we want:

  • OnPaint – Handles all the drawing methods; depending on the CommandLink’s state, it executes the proper drawing routine.
  • OnClick – Since the user control is not inheriting the Button class, if we want to be able to specify a DialogResult, the behavior needs to manually be handled here.
  • OnKeyPress – If the CommandLink is selected with Tab and the user hits Enter, then do a PerformClick.
  • OnGotFocus/OnLostFocus – Refreshes the control to draw/remove the light-blue highlight.
  • OnMouse[…] – All the OnMouse events simply change a variable to reflect the current state of the CommandLink and makes the control redraw itself.
  • OnEnabledChanged – Sets the correct state and redraws the CommandLink. (Note, unfortunately, this event is not called during design-time, but it works fine at run-time.)

Conclusion and Improvements

At the end, we are left with a control that has the basic functionality of a button but the appearance of a Vista-style CommandLink. The implementation is meant to be compatible for older versions of Windows, so there are optional improvements that can be done. For example, there is no support for gradual fading like Vista controls do, and for now, the image has to be on the left side.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

VCSKicks


Member
Visit Visual C# Kicks for more free C#.NET articles, resources, and downloads at
http://www.vcskicks.com
Location: United States United States

Other popular Button Controls articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 19 of 19 (Total in Forum: 19) (Refresh)FirstPrevNext
GeneralCommercial Version PinmemberVCSKicks21:13 8 Feb '09  
GeneralResize Issue + Simple Solution Pinmembercdgwinn7:21 19 Dec '08  
GeneralRe: Resize Issue + Simple Solution [modified] PinmemberVCKicks8:25 19 Dec '08  
GeneralRe: Resize Issue + Simple Solution Pinmemberveki-peki0:40 9 Apr '09  
GeneralGreat job - disposal exception Q Pinmemberabakshi10:46 27 Nov '08  
GeneralRe: Great job - disposal exception Q Pinmemberabakshi14:08 28 Nov '08  
GeneralRe: Great job - disposal exception Q [modified] PinmemberVCKicks8:46 29 Nov '08  
GeneralDescription Text PinmemberLateNightCoder12321:01 29 Aug '08  
GeneralRe: Description Text PinmemberVCKicks19:57 30 Aug '08  
GeneralRe: Description Text PinmemberVCKicks16:45 12 Oct '08  
GeneralNice looking Pinmembersotona22:48 18 Jul '08  
GeneralRe: Nice looking Pinmembersotona22:58 18 Jul '08  
GeneralRe: Nice looking PinmemberVCKicks11:45 19 Jul '08  
JokeRe: Nice looking Pinmembersotona2:38 21 Jul '08  
GeneralExcellent! PinmemberIndy200512:11 18 Jul '08  
GeneralI like it! PinmemberAndré Knuth5:07 18 Jul '08  
GeneralRe: I like it! PinmemberVCKicks9:01 18 Jul '08  
Generalawsome!!!! Pinmemberyassir hannoun2:55 18 Jul '08  
Generalcool! Pinmemberstrictly860:33 18 Jul '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 17 Jul 2008
Editor: Smitha Vijayan
Copyright 2008 by VCSKicks
Everything else Copyright © CodeProject, 1999-2009
Web17 | Advertise on the Code Project