Effecient form background

I was working on a C# WinFroms project, in which on of its forms has a lot of movable controls and a background image, the problem was that “Each time I try to move the controls in run time, the form background flickers and some controls disappear and then appear after I finish moving the control”.

At first glance I though that my implementation for the control movements is not efficient, I started to tweak my implementation and remove useless routines, but unfortunately the form still flickers, I tried to double buffer the form but it failed to improve performance.

After a lot of Googling and MSDNing, I found 2 blogs talking about the same issue,  after studying what they say I found that the problem was that the form spends a lot of time drawing its controls plus drawing the background image.

I didn’t know that drawing a background image on a form is an issue of performance, but now I have to say that it is, lets analyze what happen to draw an image in a very abstract way.

  • Suppose we want to put a JPEG image of size 1024 * 768 to be the background of a Form of size 800 * 600, each time the form has to draw itself it will do the following:
    1. Uncompress the JPEG image to a raw Bitmap image, as we know the JPEG is a compressed Bitmap.
    2. The resulted Bitmap image will be scaled to fit the 800 * 600 form.

Those 2 steps are what cause the form to flicker, each time the from has to redraw itself it needs to draw its controls and, uncompress the JPEG image then scaling it, so the key to improve the performance is to get rid of these redundant steps.

Following the “Render once, show a lot” principle – this is a principle from my space – we want to do those steps only once when the form is created, but how ?

The key is to provide our background image in a proper format, why not providing our image in a 800*600 Bitmap instead of 1024*768 JPEG ? so to achieve this there is 2 ways, "By logic" and the "C# geek" way, lets examine each and know the advantage and disadvantage of each.

  • "By logic" way:
    • This is no more than editing the desired background image in any photo editor (Photoshop, MS Paint) and rescale your image to 800*600 and save it as bitmap image, a peace of cake.
    • Advantage:
      • Easy, straight forward, doesn’t require any programming skills.
    • Disadvantage:
      • Each time you need to change the background image you should have to open your photo editor scale and resave the image as bitmap, this is a time wasting routine process, for me a “True programmer” is the one who utilize his programming skills to develop a solution for life.
  • "C# geek" way:
    • Why geek solution?
    • Knowing the "By logic" way we are a 1 step far from developing our elegant solution, we can make use of C# image processing capabilities (scaling, compressing and uncompressing images), so we let C# do the job for us.
    • Each form has a property named BackgroundImage of type Image, it is used to set or get the background of the form.
    • Our geek solution will be as follows:
      • We should first derive a new Form from C# WinForms Form class
      • We override the property BackgroundImage so we implement the uncompressing and scaling stuff there.
      • Look at the code below, I think the code is self-explaining.
        using System.Windows.Forms;
        using System.Drawing;
        
        class TweakedForm : Form
        {
            /// <summary>
            /// Gets or sets the background of the form
            /// </summary>
            public override Image BackgroundImage
            {
                get
                {
                    return base.BackgroundImage;
                }
                set
                {
                    if (value != null)
                    {
                        //Create a new bitmap image has same same size of the form
                        Bitmap m_bmp = new Bitmap(
                            this.Width,
                            this.Height,
                            System.Drawing.Imaging.PixelFormat.Format24bppRgb);
        
                        //Make a graphics instance that can draw on our bitmap
                        Graphics g = Graphics.FromImage(m_bmp);
        
                        //Here is the magic
                        //We want to render our compressed image to a raw bitmap image
                        //This line is like uncompressing our image and scaling it
                        g.DrawImage(value, 0, 0, m_bmp.Width, m_bmp.Height);
        
                        //Don`t forget to release your resources
                        g.Dispose();
        
                        //Assign our bitmap to the base form
                        base.BackgroundImage = m_bmp;
                    }
                    else
                    {
                        base.BackgroundImage = null;
                    }
                }
            }
        }
    • Advantage:
      • If you intend to modify the form background in future, you just need to provide the background path.
      • Generic, can be applied on any image supported by C#.
    • Disadvantage:
      • Require some geek C# knowledge, which is not that bad.

Conclusion: Always try to stick to geeks solutions, they are always elegant, this my answer to the "Why geek solution?".

Follow

Get every new post delivered to your Inbox.