Desktop Developer

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 
   LinearGradientBrush(
   rect,
   Color.Blue,
   Color.Red,
   LinearGradientMode.Vertical);
   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
   angularShape
      ( 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()
   {
      InitializeComponent();
      this.SetStyle(ControlStyles.
	  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.

About the Author

Jason Beres is the .NET technical evangelist for Infragistics Inc., a Microsoft Visual Studio Industry Partner. Jason is a Microsoft .NET MVP, is on the INETA Speakers Bureau, and is the co-chair of the INETA Academic Committee. He is the author of Sams Teach Yourself Visual Studio .NET 2003 in 21 Days (Sams) and the coauthor of Visual Basic .NET Bible (John Wiley & Sons) and C# Bible (John Wiley & Sons). Reach Jason at [email protected].

comments powered by Disqus

Featured

  • Compare New GitHub Copilot Free Plan for Visual Studio/VS Code to Paid Plans

    The free plan restricts the number of completions, chat requests and access to AI models, being suitable for occasional users and small projects.

  • Diving Deep into .NET MAUI

    Ever since someone figured out that fiddling bits results in source code, developers have sought one codebase for all types of apps on all platforms, with Microsoft's latest attempt to further that effort being .NET MAUI.

  • Copilot AI Boosts Abound in New VS Code v1.96

    Microsoft improved on its new "Copilot Edit" functionality in the latest release of Visual Studio Code, v1.96, its open-source based code editor that has become the most popular in the world according to many surveys.

  • AdaBoost Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the AdaBoost.R2 algorithm for regression problems (where the goal is to predict a single numeric value). The implementation follows the original source research paper closely, so you can use it as a guide for customization for specific scenarios.

  • Versioning and Documenting ASP.NET Core Services

    Building an API with ASP.NET Core is only half the job. If your API is going to live more than one release cycle, you're going to need to version it. If you have other people building clients for it, you're going to need to document it.

Subscribe on YouTube