View Single Post
  #4 (permalink)  
Old November 28th, 2013, 01:59 PM
Rod Stephens's Avatar
Rod Stephens Rod Stephens is offline
Wrox Author
Points: 3,166, Level: 23
Points: 3,166, Level: 23 Points: 3,166, Level: 23 Points: 3,166, Level: 23
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Jan 2006
Location: , , .
Posts: 647
Thanks: 2
Thanked 96 Times in 95 Posts
Default

Quote:
You were saying that using “Directory.GetFiles” does not return until it is finished. So I presume that is not an option for counting say 100 files, it will only produce a total count of files found..
Right. You can only display progress if your code is doing something so it can interrupt itself every now and then to make a report. Something like GetFiles runs off and doesn't give you control back until it's finished.

Quote:
1) How can I find and display every say 100 files as they are found and then all files.
2) How can I update the display in a label or listBox every time I find say 100 files.
3) How can I refresh the label or list box say every 100 files
If you use GetFiles, you can't really do these. It's quite fast so most of the time it shouldn't be an issue for only 100 files.

If you somehow search the file system yourself to look for files, then you might be able to do this. It would probably be a lot slower than GetFiles, however, so you're probably better off just letting GetFiles rip.

What you can do is show progress if you're processing files. For example, suppose you need to open 1,000 image files to make thumbnails for them. Your code would enter a loop over the file names. Every file (or 100 files or whatever) you could update the ProgressBar/Label (be sure to Refresh it so the user sees the result).

That's the sort of file operation for which you can report progress.

Quote:
4) Is the refresh done in the main program “….Button_Click(object sender,EventArgs e)” or in the “..Background worker_DoWork…”
5) Help shows refresh as “public override void Refresh () “. Not sure where this code should go.
The problem with showing progress is that the program is pounding away on the CPU in its loop so it doesn't give the user interface any time to update the controls. If you just update a Label, then it sits there on the screen unchanged until the loop ends and then after the loop finishes it quickly updates to show the final message.

A control's Refresh method makes it immediately repaint itself so you can see the new value when you change it.

Because Refresh works directly with the controls, it must be called from the UI thread. That means a BackgroundWorker's code cannot do it. The ProgressChanged event runs in the UI thread so that's where it would go. That event handler would do something like this:

Code:
    progressLabel.Text = pct.ToString() "%";
    progressLabel.Refresh();
In your example code, you're using LINQ to do the search. That will work but it does everything in one call so there's nowhere for you to pause the search once in a while to report progress.

Something like the following code would give you more control. It's a bit more work but actually might not be any slower because LINQ isn't all that fast. (This is typed off the cuff so it may need modification to run.)

Code:
    fileListBox.Items.Clear();
    DirectoryInfo dirinfo = 
        new DirectoryInfo(directoryTextBox.Text);
    int filesProcessed = 0;
    foreach (FileInfo fileinfo in dirinfo.GetFiles(pattern,
        SearchOption.AllDirectories)
    {
        // Report progress every 100 files.
        if (++filesProcessed % 100 == 0)
        {
            progressLabel.Text = "Processed " + filesProcessed.ToString() +
                " files";
            progressLabel.Refresh();
        }

        // Search the file.
        if (File.ReadAllText(fileinfo.FullName).ToLower().Contains(target) &&
            (fileinfo.LastWriteTime.Subtract(DateTime.Now).TotalDays
            >= -noDays))
        {
            // Do something with the file.
            fileListBox.Items.Add(fileinfo.Length.ToString() + "\t" +
                fileinfo.FullName + "\t" + fileinfo.LastWriteTime);
        }
    }
In this example the loop is under our control not LINQ's so we can report progress. (Note that this code would run directly in the UI thread not in a BackgroundWorker. If you want to use a BackgroundWorker, you need to use ReportProgress and ProgressChanged.)

I don't think I have time this week but next week I may be able to write some examples with and without a BackgroundWorker.
__________________
Rod

Rod Stephens, Microsoft MVP

Essential Algorithms: A Practical Approach to Computer Algorithms

(Please post reviews at Amazon or wherever you shop!)