Build a Better UI

Use the OwnerDraw capabilities of the Microsoft Windows GDI+ to add gradient colors to controls and ListBox items, add rounded edges to controls, and manage the size and color of ListBox items.

Technology Toolbox: C#, .NET Framework

Designing visually appealing user interfaces makes your applications go a long way. Your applications need to perform at top speed, but they also should be visually appealing and look and feel like other applications your target users use on a daily basis. This approach increases how quickly users accept your app, and it lessens the number of support calls they make to your help desk. Creating nice UIs is not always as easy as it seems. Most of the time, you need to think outside the box for advanced UI capabilities and go for a presentation layer toolset.

I'll show you four extremely useful tricks that will help you take your application from one that looks good to one that looks great. Using the readily available OwnerDraw capabilities of Microsoft Windows Graphics Device Interface+ (GDI+) in the .NET Framework, I'll walk you through implementing gradient colors on controls, adding rounded edges to any control, adding gradient colors to ListBox items, and managing the size and color of items in a ListBox. You can download the VS.NET project files to create an app that uses the advanced drawing capabilities of GDI+ here.

Using gradients on controls is straightforward. The only code you'll need to write occurs in the control's Paint event. This event includes the PaintEventArgs, which contains the Graphics object. The Graphics object paints the control; all you need to do is alter the output of what to paint on the label surface.

Fill in the Shape
The concept of drawing is simple. You have a shape, and you need to fill that shape with something. You can fill it with a color, a pattern, a pattern of colors, or multiple colors. The abstract Brush class in the System.Drawing namespace enables you to create instances of the SolidBrush, TextureBrush, GradientBrush, and HatchBrush classes to fill the shapes you're working with. For example, you could use code like this in the Paint event of a Label control to create a simple gradient:

Label l = (Label) sender; 

Rectangle rect = new 
   Rectangle(0, 0, l.Width, l.Height);

LinearGradientBrush lgb = new 
   e.Graphics.FillRectangle(lgb, rect);

This is fine for a plain gradient, but it doesn't take you to the next level. Your goal is to create the fancy look and feel of the Office 2003 gradients. To do this, you create a LinearGradientBrush and apply it to the rectangle of the label (see Figure 1).

This code's GetGradientBrush method creates the brush, as well as the degree at which the gradient falls off from the center of the rectangle to the edge (thus creating the multidimensional appearance). The trick is specifying the gradient's start and end colors, and how drastic the size of its falloff is with the SetBlendTriangularShape parameter values you pass:

private Brush GetGradientBrush(Rectangle bgp, 
   Color Color1, Color Color2) 
   Brush result = new LinearGradientBrush( bgp, 
      Color1, Color2, 90.0f, true );
   (result as LinearGradientBrush).SetBlendTri
      ( 0.5f, .6f );
   return result;

This code could be in the label's Paint event (see Listing 1), but it gets reused in the ListBox's DrawItem event, so make it a separate function. Notice in Listing 1 that the FillRectangle method of the Graphics class is responsible for filling the bounds of the label, defined by the height and width of the Label control as a Rectangle object.

Note than when using owner drawing controls, you need to consider not only the color of the background, but also the text in the foreground. When you call a FillRectangle or FillPath method when painting a control, only the background is painted by default. Use the Graphics class's DrawString method to paint the text of a control. The overloaded DrawString method takes parameters such as Font, FontSize, Brush, and Location when painting the text on a control.

Everybody Loves Rounded Corners
Rounded corners are not common in Windows applications, but they're all over the place in the Macintosh operating systems. They can bring a breath of fresh air to your applications and get your users excited about your Macintosh-esque app. You can easily add rounded corners to controls such as ListBox. The first step is to set the ListBox's DrawMode property enumeration to OwnerDrawFixed or OwnerDrawVariable (see Table 1 for a complete explanation of the DrawMode enumeration), its BorderStyle to None, and its BackColor to White. You aren't actually drawing round corners around the ListBox; rather, you're drawing a rounded box around the ListBox.

Create a round box with specific angles in each of the four corners by using the GraphicsPath class to define the shape of the box. The form's Paint event creates the round box around the ListBox (see Listing 2). When you create a Rectangle object the size of the ListBox and inflate it to a certain height and width, you can use the GraphicsPath class to create the rounded box around the ListBox (see Listing 3).

Back in the Visual Basic 6 days, the AutoRedraw property made sure that a form and its controls were redrawn properly during resize operations and when a form received focus. In Windows Forms, you use the ControlStyles enumeration in a form's constructor to set drawing properties:

   public Form1()
	  ResizeRedraw, true);

If you don't, you'll notice the nice rounded box doesn't look so nice when the form gets resized.

Creating the rounded box and gradient for the selected item in the ListBox means you're simply reusing the code from the gradient label example and the GetRoundBox code used to create the rounded box around the ListBox. The DrawItem event handles painting the items in the ListBox control (see Listing 4). Checking the DrawItemState enumeration enables you to determine when to draw the fancy gradient background with the rounded edges. Now you're ready to create apps your users will enjoy.


comments powered by Disqus

Subscribe on YouTube