Windows Develop Bookmark and Share   
 index > Windows Forms General > Listview Flickering
 

Listview Flickering

I have a listview control which gets updated every 3 seconds with all the processes running on my Machine . I want my control to behave just like the Process Tab on Windows Task manager .

I Am able to prevent the listview control from fickering by using the BeginUpdate and EndUpdate Method. but the problem is, it is not behaving like the windows task Manager. if I use the vertical bar and scrolls down, it get back to the begining when the listview gets updated. Again if I Select a process it unselects the moment the listview gets updated.

Can someone save me from this. Please again I want it to behave just like the Process Tab on windows Task Manager .
  • Moved byTaylorMichaelLMVP20 hours 56 minutes agoWinForms related (From:Visual C# General)
  •  
edwardkorankyi  Wednesday, October 07, 2009 8:12 PM
Don't clear the Items collection.  Add and remove items only as necessary to fill the list.  For example:

    public static void SetListItem(ListView list, ListViewItem item, int index) {
        while (list.Items.Count < index - 1) list.Items.Add("");
        list.Items[index] = item;
    }
    public static void TruncateList(ListView list, int items) {
        while (list.Items.Count > items) list.Items.RemoveAt(list.Items.Count - 1);
    }

Call SetListItem while you iterate the process collection, TruncateList when you're done.
Hans Passant.
nobugz  Wednesday, October 07, 2009 9:48 PM
The native ListView control has excellent flicker suppression with double-buffering, .NET supports it.  Add a new class to your project and paste the code shown below.  Compile.  Drop the new control from the top of the toolbox onto your form.  You'll still want to use Begin/EndUpdate(), it makes updating the list a lot quicker.

using System;
using System.Windows.Forms;

public class MyListView : ListView {
  public MyListView() {
    this.DoubleBuffered = true;
  }
}

Hans Passant.
nobugz  Thursday, October 08, 2009 2:47 AM
There is a complication, you can't let the ListView do the sorting.  That shuffles the items internally and prevent a proper update.  Disabling the sorting, then enabling it again after the update causes the scrollbar to reset.  This worked well:

    private void LoadProccessList() {
      System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcesses();
      Array.Sort(processes, new Comparison<System.Diagnostics.Process>(
        (p1, p2) => string.Compare(p1.ProcessName, p2.ProcessName))
      );
      lstProcesses.BeginUpdate();
      int count = 0;
      foreach (System.Diagnostics.Process proc in processes) {
        try {
          ListViewItem item = new ListViewItem();
          item.Text = proc.ProcessName;
          item.SubItems.Add(proc.Id.ToString());
          //...
          if (lstProcesses.Items.Count > count) lstProcesses.Items[count] = item;
          else lstProcesses.Items.Add(item);
          ++count;
        }
        catch { }
      }
      while (lstProcesses.Items.Count > count)
        lstProcesses.Items.RemoveAt(lstProcesses.Items.Count - 1);
      lstProcesses.EndUpdate();
    }

Hans Passant.
nobugz  Thursday, October 08, 2009 3:48 AM
I'm guessing that you still use lstProcesses.Sort().  Yes, you'll have to restore the selection after the update, it might have moved.

Hans Passant.
nobugz  Thursday, October 08, 2009 4:11 AM
Don't clear the Items collection.  Add and remove items only as necessary to fill the list.  For example:

    public static void SetListItem(ListView list, ListViewItem item, int index) {
        while (list.Items.Count < index - 1) list.Items.Add("");
        list.Items[index] = item;
    }
    public static void TruncateList(ListView list, int items) {
        while (list.Items.Count > items) list.Items.RemoveAt(list.Items.Count - 1);
    }

Call SetListItem while you iterate the process collection, TruncateList when you're done.
Hans Passant.
nobugz  Wednesday, October 07, 2009 9:48 PM
Thanks though but I don't get it. This is my method that Populate my list view.
Can you please help me using that?

Where lstProcesses is the name of my list view

private void LoadProccessList()
        {
          
                //Get All the curent Process of the System//
                System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcesses();

                lstProcesses.BeginUpdate();
                lstProcesses.Items.Clear();

                //Prevents lstProcess from repainting               

                //Load all the cureent processors Running//
                //Loop throug and grap all the need processes//
                foreach (System.Diagnostics.Process proc in processes)
                {
                    ListViewItem newItems = new ListViewItem();
                    newItems.Text = proc.ProcessName;
                    newItems.SubItems.Add(proc.Id.ToString());
                    newItems.SubItems.Add(proc.Responding.ToString());
                    newItems.SubItems.Add(string.Format("{0:###,###,###} K", proc.PeakWorkingSet64 / 1024));
                    newItems.SubItems.Add(proc.HandleCount.ToString());
                    newItems.SubItems.Add(proc.Threads.Count.ToString());

                    lstProcesses.Items.Add(newItems);
                }
                lstProcesses.Sort();
                lstProcesses.EndUpdate();

            }
edwardkorankyi  Thursday, October 08, 2009 2:21 AM
Hi,

I believe this is what NoBugz is suggesting;

		private void LoadProccessList()
		{
			//Get All the curent Process of the System//
			System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcesses();

			lstProcesses.BeginUpdate();

			//Prevents lstProcess from repainting                

			//Load all the cureent processors Running//
			//Loop throug and grap all the need processes//
			foreach (System.Diagnostics.Process proc in processes)
			{
				ListViewItem item = lstProcesses.Items[proc.Id.ToString()];
				if (item == null)
					item = lstProcesses.Items.Add(proc.Id.ToString(), proc.ProcessName, 0);

				item.Text = proc.ProcessName;
				item.SubItems.Add(proc.Id.ToString());
				item.SubItems.Add(proc.Responding.ToString());
				item.SubItems.Add(string.Format("{0:###,###,###} K", proc.PeakWorkingSet64 / 1024));
				item.SubItems.Add(proc.HandleCount.ToString());
				item.SubItems.Add(proc.Threads.Count.ToString());
			}

			lstProcesses.Sort();
			lstProcesses.EndUpdate();

		}<br /><br />
Note the item is added with the process id as it's key, before we add the item we check to see if an item with that id (key) already exists in the list and if so we update it instead of adding it again, and we remove the code that clears the entire list.

There are two problems with this code;

1. It still flickers on my PC, even with double buffering turned on in the form properties, the sort removed, and the begin/end update removed. It flickers less than your original solution however, and it won't reset the selected item whenever the list loads etc. You could perhaps reduce the flicker somewhat by only updating columns where the new value was actually different from the old one, but I'm not sure even that will eliminate the flicker entirely.

2. It doesn't clear out processes that have died... extra logic would be needed to make that work. You would have to look for items in the list view that aren't in the process list and remove them from the list view, which would also probably cause some more flicker when processes were removed.


Yort  Thursday, October 08, 2009 2:34 AM
The native ListView control has excellent flicker suppression with double-buffering, .NET supports it.  Add a new class to your project and paste the code shown below.  Compile.  Drop the new control from the top of the toolbox onto your form.  You'll still want to use Begin/EndUpdate(), it makes updating the list a lot quicker.

using System;
using System.Windows.Forms;

public class MyListView : ListView {
  public MyListView() {
    this.DoubleBuffered = true;
  }
}

Hans Passant.
nobugz  Thursday, October 08, 2009 2:47 AM
I am getting confuse. Can you please give me an example base on my code. I tried the above but still don't work. Please help me.
edwardkorankyi  Thursday, October 08, 2009 3:16 AM
I tried what you typed it didn't work.
edwardkorankyi  Thursday, October 08, 2009 3:39 AM
Sorry I meant I tried what you typed it didn't work.
edwardkorankyi  Thursday, October 08, 2009 3:47 AM
There is a complication, you can't let the ListView do the sorting.  That shuffles the items internally and prevent a proper update.  Disabling the sorting, then enabling it again after the update causes the scrollbar to reset.  This worked well:

    private void LoadProccessList() {
      System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcesses();
      Array.Sort(processes, new Comparison<System.Diagnostics.Process>(
        (p1, p2) => string.Compare(p1.ProcessName, p2.ProcessName))
      );
      lstProcesses.BeginUpdate();
      int count = 0;
      foreach (System.Diagnostics.Process proc in processes) {
        try {
          ListViewItem item = new ListViewItem();
          item.Text = proc.ProcessName;
          item.SubItems.Add(proc.Id.ToString());
          //...
          if (lstProcesses.Items.Count > count) lstProcesses.Items[count] = item;
          else lstProcesses.Items.Add(item);
          ++count;
        }
        catch { }
      }
      while (lstProcesses.Items.Count > count)
        lstProcesses.Items.RemoveAt(lstProcesses.Items.Count - 1);
      lstProcesses.EndUpdate();
    }

Hans Passant.
nobugz  Thursday, October 08, 2009 3:48 AM
I tried it, it seems adding the process names twice.the scroll bar doesn't reset that works fine but the problem is when I select a row of process, it unselects again. I wanted it to behave like the Windows task Manager.
edwardkorankyi  Thursday, October 08, 2009 4:07 AM
I'm guessing that you still use lstProcesses.Sort().  Yes, you'll have to restore the selection after the update, it might have moved.

Hans Passant.
nobugz  Thursday, October 08, 2009 4:11 AM
my bad it works. you are right. But the Select doesn't work. each time I select a process, it Unselects. can you please help me with that. That though.
edwardkorankyi  Thursday, October 08, 2009 4:13 AM
is there any trick i would  use to maintain the selection from not reseting
edwardkorankyi  21 hours 23 minutes ago
Hi edwardkorankyi,

You need to store the selected process names in some varialbes and select them again after the ListView is refreshed.

Regards,
Aland Li
Please mark the replies as answers if they help and unmark if they don't. This can be beneficial to other community members reading the thread.
Aland Li  2 hours 42 minutes ago

You can use google to search for other answers

Custom Search

More Threads

• Loading picturebox dynamically into a panel
• Custom Toolbox with User Controls
• Software Application Development in Minimum Time
• MouseMove in a form
• Add Custom Localization Languages?
• .Focus() method
• Control Pixels
• Calling a Dialog Button Control
• Windows form control question
• How to set normal link to visited on WebBrowser control?