Solved

Most Efficient way to refresh ListViews (Windows.Forms)

Posted on 2004-09-01
5
366 Views
Last Modified: 2008-03-17
Whats the most efficient way to refresh a ListView control in Windows.Forms that is reflecting the file system.

I.e. I currently have a listview that i populate with files from a directory.  A timer keeps updating the listview to add listviewitems to represent files that appear on the file system and aren't yet in the listview, and to remove items that reflect files that are no longer on the file system.

I am discovering that when there are a lot of files in the directory, there is a massive performance hit that i really want to eliminate or at least minimise.

My current (inefficient) code centers around two methods, one to add new files the other to clear removed files, that might need the following clarifications:
- The xmlnode is part of the strategy i use to populate tree and list views dynamically - so you don't have to worry about understanding that.
- createFileItem(node, file) creates a new listviewitem that represents the file on the file system.
- IsFile((string)item.Tag) tells me if a listviewitem represents a file on the filesystem

private void insertAddedFiles(ListView listView, XmlNode node, string[] files)
{
      foreach (string file in files)
      {
            bool present = false;
            foreach (ListViewItem item in listView.Items)
            {
                  if (item.SubItems[0].Text == Path.GetFileName(file))
                  {
                        present = true;
                        break;
                  }
            }
            if (!present)
            {
                  ListViewItem item = createFileItem(node, file);
                  if (item != null)
                        listView.Items.Add(item);
            }
      }
}

private void clearRemovedFiles(ListView listView, string directory)
{
      foreach (ListViewItem item in listView.Items)
      {
            if (IsFile((string)item.Tag) && !File.Exists(Path.Combine(directory, item.SubItems[0].Text)))
                  item.Remove();
      }
}

I plan to try out your suggestions and will award points primarily to the most efficient, but I also think elegance is important.
0
Comment
Question by:pashcroft
  • 3
  • 2
5 Comments
 
LVL 10

Expert Comment

by:eternal_21
ID: 11959855
Questions:

  1. Does the ListView contents match the current files in a single specific directory?  I mean, if we have 100 files in a folder, does the ListView contain exactly 100 items?

  2. It is important that you track file creations and deletions as opposed to just reading the directory and generating a new ListView?

  3. How time-consuming is the createFileItem(XmlNode, string) method?
0
 
LVL 10

Accepted Solution

by:
eternal_21 earned 500 total points
ID: 11959986
Anyway, without the answers to the above questions, here is some optimized code:

    System.Collections.SortedList sortedList = new SortedList();

    private void insertAddedFiles(ListView listView, XmlNode node, string[] files)
    {
      foreach(string file in files)
        if(!sortedList.Contains(file))
        {
          ListViewItem item = createFileItem(node, file);
          if (item != null)
          {
            listView.Items.Add(item);
            sortedList.Add(file, item);
          }
        }
    }

    private void clearRemovedFiles(ListView listView, string directory)
    {
      System.Collections.ArrayList dirList = new System.Collections.ArrayList();
      dirList.AddRange(System.IO.Directory.GetFiles(directory));

      string[] listFiles = new string[sortedList.Keys.Count];
      sortedList.Keys.CopyTo(listFiles, 0);
      foreach(string file in listFiles)
        if(!dirList.Contains(file))
        {
          ((ListViewItem)sortedList[file]).Remove();
          sortedList.Remove(file);
        }
    }
0
 
LVL 4

Author Comment

by:pashcroft
ID: 11960303
Answers for eternal:

  1. Does the ListView contents match the current files in a single specific directory?  I mean, if we have 100 files in a folder, does the ListView contain exactly 100 items?

yes and no: the listview is actually filtered on multiple patterns, but it will show all the files match for match (eg: i'm showing for one directory *.log, *.csv and info.txt patterns, so the list will show the 12 .log files, the 2 csv files and the one info.txt file, but wont show any other files)

  2. It is important that you track file creations and deletions as opposed to just reading the directory and generating a new ListView?

yes.  i want (need?) list view to stay same unless a file:
- changes name (new listitem added, old list item removed),
- gets created/moved in (new listitem added) or
- gets deleted/moved out (old list item removed)

  3. How time-consuming is the createFileItem(XmlNode, string) method?

efficient as can be (uses a fileinfo object to retrieve filename, size and date to create a listitem) - but i still want to avoid just recreating all the listitems (because drawing them is noticable).
0
 
LVL 4

Author Comment

by:pashcroft
ID: 11960564
I've just reworked eternal's suggestion (see below), and it seems to be working nicely (reducing 100% cpu to around 25%)

I've opted for straight arrays where i could (less overhead) and gone for a hashtable over a sortedlist (no real need to sort)

Eternal, let me know what you think.

Everyone else, i'll be awarding to eternal unless anyone can significantly improve on this:

I'll be adding another question on the most efficient way to compare two arrays (C#) - so check for that one too :)

private Hashtable _fileSystemContents = new Hashtable();

private void insertAddedFiles(ListView listView, XmlNode node, string[] files)
{
      foreach (string file in files)
      {
            if (!_fileSystemContents.ContainsKey(file))
            {
                  ListViewItem item = createFileItem(node, file);
                  if (item != null)
                  {
                        listView.Items.Add(item);
                        _fileSystemContents.Add(file, item);
                  }
            }
      }
}

private void clearRemovedFiles(ListView listView, string directory)
{
      string[] files = Directory.GetFiles(directory);
      string[] keys = new string[_fileSystemContents.Count];
      _fileSystemContents.Keys.CopyTo(keys, 0);
      foreach (string key in keys)
      {
            if (Array.BinarySearch(files, key) < 0)
            {
                  listView.Items.Remove((ListViewItem)_fileSystemContents[key]);
                  _fileSystemContents.Remove(key);
            }
      }
}
0
 
LVL 10

Expert Comment

by:eternal_21
ID: 11964807
> I've opted for straight arrays where i could (less overhead) and gone for a hashtable over a sortedlist (no real need to sort)

Yes, I meant to change that... a HashTable will be faster than a SortedList!

> but i still want to avoid just recreating all the listitems (because drawing them is noticable)

If drawing the items is the problem, try using ListView.BeginUpdate() and then add/remove your items.  When you are finished call ListView.EndUpdate() and your ListView will be updated.
0

Featured Post

Are your AD admin tools letting you down?

Managing Active Directory can get complicated.  Often, the native tools for managing AD are just not up to the task.  The largest Active Directory installations in the world have relied on one tool to manage their day-to-day administration tasks: Hyena. Start your trial today.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

We all know that functional code is the leg that any good program stands on when it comes right down to it, however, if your program lacks a good user interface your product may not have the appeal needed to keep your customers happy. This issue can…
Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
Nobody understands Phishing better than an anti-spam company. That’s why we are providing Phishing Awareness Training to our customers. According to a report by Verizon, only 3% of targeted users report malicious emails to management. With compan…
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

809 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question