Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

InfoBarLite Control

0.00/5 (No votes)
18 Sep 2002 1  
This article shows how to create a Windows.Forms control by using C#.

Sample Image 1 - InfoBarLite1.jpg

Sample Image 2 - InfoBarLite2.jpg

Introduction

Ever since Microsoft started using a nice GUI style that shows brief information at the top of setup forms, I wanted to have one of my own. The screen shot shown above display a sample of such a control. I first created this control as an OCX with VB6 and used it in several projects. VB6 version required heavy use of Win32 API functions. However, to learn C# syntax, I decided to create the same control, I call it InfoBarLite, with this new language. After starting to code, I found out that life was much better with C#.

The control has some very nice features to make things easier:

  • The control can have both a background image and a separate image.
  • The image can be aligned in 9 different ways. Additionally, the image can be positioned by using x and y offset properties.
  • Two different text properties are provided each of which can have multiple lines separated by Environment.NewLine character.
  • Each text property has its own Font, ForeColor, OffsetX, and OffsetY properties.
  • Background color of the control can be either solid or gradient.
  • The control can have 9 different border styles for all sides or for each side.
  • It can be used either as a header bar or as a side bar.

Details

The InfoBarLite control is derived from System.Windows.Forms.UserControl as shown below:

public class InfoBarLite : System.Windows.Forms.UserControl
{    // Actual code

    ...
}

The most interesting part of the control is OnPaint event as this is the usual case for owner-drawn controls. First, the background information is drawn. This information is defined by BackStyle, BorderSide, and BoderStyle properties. One point I want to stress out is that the behavior of the control. if the BackStyle is Gradient, the background image is not drawn. This means that BackStyle property has precedence over BackgroundImage property. In contrast, if the BackStyle is Solid, the BackColor property is ignored. This behavior is by design. Of course, it can easily be changed by modifying the overridden OnPaint event. Now, here is the OnPaint method:

   /// <summary>

   /// Overloaded Paint method

   /// </summary>

   /// <param name="pe">PaintEventArgs</param>

   protected override void OnPaint(PaintEventArgs pe)
   {
      // First, repaint the base class

      base.OnPaint(pe);

      Rectangle r = this.ClientRectangle;

      // Draw the background and border(s)

      switch( this.BackStyle )
      {
         case BackStyle.Gradient:  
            LinearGradientBrush gb = new LinearGradientBrush(r, 
                                           this.GradientStartColor, 
                                           this.GradientEndColor,
                                           this.GradientMode);
            if(this.BorderSide == Border3DSide.All)
            {
               ControlPaint.DrawBorder3D(pe.Graphics, r, 
                  this.BorderStyle, this.BorderSide);
                  r.Inflate(-2, -2);
               pe.Graphics.FillRectangle(gb, r);
            }
            else
            {
               pe.Graphics.FillRectangle(gb, r);
               ControlPaint.DrawBorder3D(pe.Graphics, r, 
                     this.BorderStyle, this.BorderSide);
            } 
            gb.Dispose();
            break;

         case BackStyle.Solid:
            if(this.BorderSide == Border3DSide.All) 
            {  
               ControlPaint.DrawBorder3D(pe.Graphics, r, 
                       this.BorderStyle, this.BorderSide);
               r.Inflate(-2, -2);
               SolidBrush sb = new SolidBrush(this.BackColor);
               pe.Graphics.FillRectangle(sb, r); 
               sb.Dispose();
            }
            else
            {
               ControlPaint.DrawBorder3D(pe.Graphics, r, 
                        this.BorderStyle, this.BorderSide);
            }
   
            break;
   
         default:
            ControlPaint.DrawBorder3D(pe.Graphics, r, 
                        this.BorderStyle, this.BorderSide);
            break;
      }

      // Set variables for Image and Text drawing

      StringFormat fmt = new StringFormat();
      fmt.FormatFlags = StringFormatFlags.MeasureTrailingSpaces | 
      StringFormatFlags.DisplayFormatControl |
      StringFormatFlags.FitBlackBox;
      fmt.Trimming = StringTrimming.EllipsisCharacter;

      // Rectangle variables that will be calculated

      RectangleF rImage = new RectangleF(0,0,0,0);
      RectangleF rText1 = new RectangleF(0,0,0,0);
      RectangleF rText2 = new RectangleF(0,0,0,0);

      SizeF sizeText1 = pe.Graphics.MeasureString(this.Text1, 
                      this.Text1Font, ClientRectangle.Size, fmt);
      SizeF sizeText2 = pe.Graphics.MeasureString(this.Text2, 
                      this.Text2Font, ClientRectangle.Size, fmt);

      // Calculate the rectangles before starting to draw

      this.getRects(ref rImage, ref rText1, 
                              sizeText1, ref rText2, sizeText2);

      // Draw the image and the texts

      if(this.Enabled)
      {
         int iImageWidth = 0;
        
         if( this.m_Image != null )
         {
            pe.Graphics.DrawImage(this.m_Image, rImage);
            iImageWidth = this.m_Image.Width;
         } 

         SolidBrush sb = new SolidBrush(this.Text1ForeColor);
         pe.Graphics.DrawString(this.Text1, 
                 this.Text1Font, sb, rText1, fmt);
        
         sb = new SolidBrush(this.Text2ForeColor);
         pe.Graphics.DrawString(this.Text2, this.Text2Font, 
                 sb, rText2, fmt);

         sb.Dispose();
       }
       else
       {
          if( this.m_Image != null )
             ControlPaint.DrawImageDisabled(pe.Graphics, 
                               this.m_Image, (int) rImage.X, (int) rImage.Y, 
                               SystemColors.ControlLight);

          ControlPaint.DrawStringDisabled(pe.Graphics, 
                               this.Text1, this.Text1Font, 
                               SystemColors.ControlLight,
                               rText1, 
                               fmt);

         ControlPaint.DrawStringDisabled(pe.Graphics,
                               this.Text2, this.Text2Font, 
                               SystemColors.ControlLight,
                               rText2,
                               fmt);
      }
   }

Usage

It should be very easy to use this control. Just drop it in a form, set the desired properties, and that's all. A sample which is very similar to Nero's screen is shown below:

Sample Image 2 - InfoBarLite3.jpg

Figure 3 - A sample demo screen showing the control as a side bar and as a header bar.

Know issues/limitations

There are some issues that need to be fixed and/or added.

  • When the control is used as a sidebar, text properties are not drawn rotated (vertical), but this is by design.
  • The Font property inherited from UserControl class should not be visible to the user. Currently, I don't know how to do it; therefore, any suggestions will be appreciated.
  • When the Enabled property is changed through the property window (in design mode), this change is not reflected to the control. On the other hand, if this property is changed via code, the control acts as expected. Once again, I require suggestions on this issue.
  • The last limitation is that the control is not globalization aware. In VS IDE, if you set the Form's Localizable property to True, the IDE automatically adds code to retrieve the correct text of native controls (comes with VS.NET) that will reflect the CurrentCulture via resource manager. I guess this is the easiest way to localize an application. Currently, the InfoBarLite doesn't cooperate with the IDE to accomplish this task. If someone knows how to do it and sends the solution, I can update the control to benefit everybody.

Conclusion

Hopefully, the InfoBarLite control will make my fellow developers' life easier as it did mine. It will also allow you to add a very nice user interface feature that will help you to increase end-user experience. If you look at Figure 1, this control will increase the understandability of the forms we create for users, as they will now have more descriptive information about what is needed from him/her. Traditionally, this kind of information is displayed in a StatusBar control. However, most of the users are not happy, at least my users, because they are being forced to read such small letters. The InfoBarLite control attempts to solve aforementioned usability problems. It can display two different styles of text and an image. The image might describe the task required to be achieved better than text as most people tend not to read descriptions. It's suggested to be used in dialog boxes, but, of course, it's up to you.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here