2

I have a ListView which I populate with a lot of items, over 3000. This can take up to 15 seconds. Every time I add an item I want to update a label stating how many items have been added so far. To do so I use this code:

foreach (FileInfo f in dir.GetFiles("*.*", SearchOption.AllDirectories))
{
    DateTime dt = GetDateTakenFromImage(Path.Combine(f.Directory.ToString(), f.Name));
    count++;
    labelLoadedLeft.Text = "Loading " + count + " files so far";
    ListViewItem lSingleItem = lv.Items.Add(f.Name);

    lSingleItem.SubItems.Add(dt.ToString("dd MMMM yyyy"));
    lSingleItem.Tag = Path.Combine(f.Directory.ToString(), f.Name);
}

Unfortunately the label does not show until all items have been loaded.

I understand this has to do with the fact that I am doing a lengthy operation on thr UI thread and that I should probably be using a backgroundworker to do the work.

Does anyone know of good and simple examples on how to use background worker. What I have found so far is too complicated for me or too convoluted.

Thank you

Crouz

3
  • Have you seen this tutorial? dotnetperls.com/backgroundworker Commented Nov 26, 2012 at 15:45
  • 2
    Aside of threading, you could make your inserting operation more efficient either by calling BeginUpdate\EndUpdate methods on a list view, or just inserting all items at once using AddRange. Commented Nov 26, 2012 at 15:46
  • Thanks guys, I'll look these up as soon as I get back home Commented Nov 26, 2012 at 15:53

4 Answers 4

1

If you only want your Label to update, you should update it.

labelLoadedLeft.Text = "Loading " + count + " files so far";
labelLoadedLeft.Update();

Which version of VS/C# do you use? With VS2012/C#5.0 you could take advantage of the new "await" feature. It makes code easy to read and updating the UI can be done without invoke etc

Sign up to request clarification or add additional context in comments.

1 Comment

Hi,thank you for the answer, this is working fine, although the entire operation seems a little slower, maybe me though. I use VS2010
1

You can do it with a BackgroundWorker, here's an example, http://dotnetforum.net/topic/34729-how-to-cancel-backgroundworker-during-getfiles/.

However, the UI will never show anything until the you get a list of all files. And as you said this is slow.

Use the EnumerateFiles method, http://msdn.microsoft.com/en-us/library/dd383458(v=vs.100).aspx, which returns one file at a time.

1 Comment

As @YYY mentioned, TPL is better than a BackgroundWorker. But you still must use EnumerateFiles to get a zipping UI.
1

A background worker is most easily handled via the TPL, presuming you're working with .NET 4.0. You can start a worker in the background using code that looks like this:

Task.Factory.StartNew( () =>
{
   // Background Worker Stuff goes here
}, TaskCreationOptions.LongRunning);

You can then put your worker's job in another class/function, and have it yield return its results from DoWork(), giving you an IEnumerable<T> of whatever it's returning. Using your foreach loop over that like so:

foreach(var item in DoWork())
{
   // Update UI
}

Will mean you can update the UI as results come back. Yield return will allow you to handle items before the entire enumerable returns. Be careful, though - yield return implicitly sets up a state machine inside your program, so unless you need functionality like this it can be very wasteful to use this idiom.

Comments

0

You may not need it. Use Begin/EndUpdate on the ListView.

http://msdn.microsoft.com/en-us/library/system.windows.forms.listview.beginupdate.aspx

This will prevent drawing of the items until they're all loaded. You won't be able to maintain a count, but I don't really see the benefit of that at all, especially if this makes it too fast to matter.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.