?
Solved

Most Efficient way to refresh ListViews (Windows.Forms)

Posted on 2004-09-01
5
Medium Priority
?
377 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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 2000 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

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

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

Introduction Hi all and welcome to my first article on Experts Exchange. A while ago, someone asked me if i could do some tutorials on object oriented programming. I decided to do them on C#. Now you may ask me, why's that? Well, one of the re…
Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
Visualize your data even better in Access queries. Given a date and a value, this lesson shows how to compare that value with the previous value, calculate the difference, and display a circle if the value is the same, an up triangle if it increased…
In this video, Percona Director of Solution Engineering Jon Tobin discusses the function and features of Percona Server for MongoDB. How Percona can help Percona can help you determine if Percona Server for MongoDB is the right solution for …
Suggested Courses

765 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