C# Tips

C# Tip Article

How to prevent flicker in WinForms Control

If you frequently update the content of a WinForms Control, you might observe a flicker issue. This flicker issue often occurs when the content data is large.

Take this example. The code below has a listview that shows file list of System32 folder and it updates a listview column every second. If you run this code, you will likely observe a flicker issue in the ListView control.

private void Form1_Load(object sender, EventArgs e)
{
    //listView1.DoubleBuffered(true);

    string currDir = @"C:\Windows\System32"; 
    DirectoryInfo di = new DirectoryInfo(currDir);
    FileInfo[] files = di.GetFiles();

    listView1.BeginUpdate();
    listView1.View = View.Details;

    foreach (var fi in files)
    {
        ListViewItem lvi = new ListViewItem(fi.Name);
        lvi.SubItems.Add("");                
        listView1.Items.Add(lvi);
    }

    listView1.Columns.Add("Filename", 100, HorizontalAlignment.Left);
    listView1.Columns.Add("Comment", 100, HorizontalAlignment.Left);                        
    listView1.EndUpdate();            

    Timer timer1 = new Timer();
    timer1.Interval = 1000;
    timer1.Tick += (s,ea) =>
    {
        listView1.BeginUpdate();
        for (int i = 0; i < listView1.Items.Count; i++)
        {
            listView1.Items[i].SubItems[1].Text = DateTime.Now.Second.ToString();
        }
        listView1.EndUpdate();
    };
    timer1.Enabled = true;
}

One way of solving this flicker issue is to use so-called double buffering. Double buffering is using secondary buffer to prevent flicker.

In WinForms, Form class has a public property called "DoubleBuffered", but it only applied to the Form itself and does not apply to child controls. In Control class, there is "DoubleBuffered" property but it is a protected property. So in order to use the protected property, you either have to create a subclass or access the property using some other methods such as reflection.

public class Control
{
    //...(elided)....
	
	// Summary:
	//     Gets or sets a value indicating whether this control should redraw its surface
	//     using a secondary buffer to reduce or prevent flicker.
	//
	// Returns:
	//     true if the surface of the control should be drawn using double buffering; otherwise,
	//     false.
	protected virtual bool DoubleBuffered { get; set; }
}

Sometimes subclassing makes sense but in many cases using reflection might be easier. Here is an extension method that uses .NET reflection to update "DoubleBuffered" property.

public static class Extensions
{
    public static void DoubleBuffered(this Control control, bool enabled)
    {
        var prop = control.GetType().GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
        prop.SetValue(control, enabled, null);
    }
}

Once the extension method is written, then we can call this method once in the program. (In the example above, uncomment this code at the top of Form1_Load)

listView1.DoubleBuffered(true);

This double buffering can be applied to other controls in WinForms.