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

GraphicsBuffer Class - Buffering of Dynamic Visual States for Controls

0.00/5 (No votes)
2 Aug 2004 1  
This article discusses the usage of a custom class that caches custom images. The class, GraphicsBuffer, is best used to cache visual states for controls without concern for control flicker and unnecessary processor usage.

Introduction

Owner-drawn UserControls with dynamic user interfaces usually have several distinct visual states. As you begin to write one of these controls, you will soon notice that controls which require a lot of painting to change states tend to flicker and, depending on the complexity of the painting operation, the user may experience a lag while the control is repainted. While the flicker problem can be dealt with by setting the ControlStyles.DoubleBuffer style on the control, this doesn't address processor lag problem. The class described in this article addresses both of these problems by providing an easy way to cache the different visual states a control may have. The demo application illustrates the use of this class by creating a simple button control with three states, a normal state, a mouse-over state, and a mouse-down state.

Background

The topics discussed in this article are very simple and should be easy to understand for most people. However, it is assumed that you have some experience with the creation of UserControls and GDI+.

The source is divided into two projects, GraphicsBuffer and GraphicsBufferText. The GraphicsBuffer project contains the source for the GraphicsBuffer class and the GraphicsBufferTest project contains the code for the demo control that uses the GraphicsBuffer class. The projects were both created in Visual Studio .NET 2003 but none of the code uses constructs that were not available in the earlier Visual Studio .NET release.

Using the GraphicsBuffer Object

Using the GraphicsBuffer object is a three-step process:

  1. Create the buffer.
  2. Write to the buffer with standard GDI+ method calls.
  3. Pull the cached image from the object and draw it on the target control.

1. Creating the buffer

To create a buffer for your image, the GraphicsBuffer object requires you to specify a key and image size for the buffer. The key is used to access the buffer later. The size of the image buffer cannot be changed once the buffer is created, but it can be discarded and a new one created. If the buffer is used to cache the visual state of a control, the size of the buffer should be the same size as the control.

  //Create the GraphicsBuffer object and then create three 

  //100x50 px buffer called Normal, MouseDown, and MouseOver

  GraphicsBuffer _graphicsBuffer = new GraphicsBuffer();
  _graphicsBuffer.Create("Normal",100,50);
  _graphicsBuffer.Create("MouseDown",100,50);
  _graphicsBuffer.Create("MouseOver",100,50);

2. Writing to the buffer

The buffer exposes a Graphics object through its indexer. The key for the indexer is the name specified when the buffer was created. Because the Graphics object is exposed, all standard drawing functionality is available. The code below draws a gradated background on the buffer, creates a solid border, and draws some text in the center of it.

  Graphics g; Rectangle rect;

  StringFormat sf = new StringFormat();
  sf.Alignment = StringAlignment.Center;
  sf.LineAlignment = StringAlignment.Center;
  rect = new Rectangle(0,0,100,50);

  //draw normal state

  g = _graphicsBuffer["Normal"];
  Brush b = new LinearGradientBrush (rect, 
            Color.FromArgb(125,125,150), 
            Color.FromArgb(150,150,200),45F,true);
  g.FillRectangle(b,rect);
  g.DrawRectangle(new Pen(Color.FromArgb(125,125,175),1), rect);
  g.DrawString("Hello World",new Font("Arial",10), 
                new SolidBrush(Color.White),rect,sf);

As a practical suggestion, I would recommend wrapping the code which draws to the buffer in a function block so that it can be called within your application at any time. This is because, there are several situations where you may want to scrap the image in the buffer and rebuild it. For example, if your image depends on the size of the control it's displayed on, then it will need to get recreated when the control is resized. Also, there could be several properties of your control which may affect the visual appearance of your control. When any one of those properties is changed, the buffer will need to be rebuilt. To discard the contents of the buffer, you could use the Clear() or Remove() methods.

  //clear all buffered images

  _graphicsBuffer.Clear();

  //remove a single image from the buffer

  _graphicsBuffer.Remove("Normal");  //removes the item with the "Normal" key

3. Display Cached Image on Control

To retrieve a cached image from the control, use the GetImage() method. In more cases than not, this would be used in the Paint event of your control.

  private void BufferedButton_Paint(object sender, 
                         System.Windows.Forms.PaintEventArgs e)
  {
    e.Graphics.DrawImage(_graphicsBuffer.GetImage("Normal"), 
                                         this.ClientRectangle);
  }

The example above always draws the "Normal" state for the control. In your application, you would probably have a switch statement to select between the different possible states to be displayed. The code in the demo project illustrates this concept.

Conclusion

By itself, the code in the GraphicsBuffer class is nothing revolutionary. The extreme coolness comes from the crispness it adds to your controls when you write code structured to use it. When the class is used properly, your control only repaints itself exactly as many times as it needs to. Too many controls repeat all of their drawing procedures every time the Paint event is fired. Using this simple class will create a measurable improvement in the professionalism in your controls and applications.

History

  • August 3, 2004 - Initial creation.

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