Solved

Most Efficient way to refresh ListViews (Windows.Forms)

Posted on 2004-09-01
5
369 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

Networking for the Cloud Era

Join Microsoft and Riverbed for a discussion and demonstration of enhancements to SteelConnect:
-One-click orchestration and cloud connectivity in Azure environments
-Tight integration of SD-WAN and WAN optimization capabilities
-Scalability and resiliency equal to a data center

Question has a verified solution.

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

It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
The article shows the basic steps of integrating an HTML theme template into an ASP.NET MVC project
In an interesting question (https://www.experts-exchange.com/questions/29008360/) here at Experts Exchange, a member asked how to split a single image into multiple images. The primary usage for this is to place many photographs on a flatbed scanner…

830 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