views:

185

answers:

1

Hello,

I do some operation on "big" file (around 4Mb)

I do this : 1. Get all files from a directory and place them in an IList MyInfoClass has properties : name, extension, fullPath, creationDate, contentPart 2. I do a Linq query to get only some extension type. 3. I loop on the Linq query result and for each, I open the file, do some operation (get value) and put the result in MyFileIno.ContentPart.

FYI : 30 files, it's a 14sec operation

That's work.

The problem, when I run my library from the UI, when I click the button, the window freeze during operation time. I'd like :

  1. a solution to not freeze the form
  2. see the progress operation

Could you give me the best practice to solve this kind of problem ?

Thanks,

Code

public class FileManager 
{
    public string CurrentFileName { get; set; }
    public void Validation(string path)
    {
     IList<InfoFile> listFile = GetListFile(path);
     foreach (InfoFile item in listFile)
     {
      CurrentFileName = item.Name;
      .....
     }
    }
}


private void button1_Click(object sender, EventArgs e)
{
    var worker = new BackgroundWorker();
    worker.DoWork += (s, args) =>
    {
     int percentProgress = 6;
     FileManager fileManager = new FileManager();
     fileManager.Validation(@"C:.....");
     ((BackgroundWorker)s).ReportProgress(percentProgress, fileManager.CurrentFileName);
    };

    worker.ProgressChanged += (s, args) =>
    {
     var currentFilename = (string)args.UserState;
     label1.Text = currentFilename;
     progressBar1.Value = args.ProgressPercentage;
    };

    worker.RunWorkerCompleted += (s, args) =>
    {
     progressBar1.Value = 0;
    };
    worker.RunWorkerAsync();
}
+9  A: 

The application freezes because you are performing the file parsing in the main thread. You could use BackgroundWorker to perform operation on a new thread. Here's some pseudo code that might help you to get started:

private void button1_Click(object sender, EventArgs e)
{
    var worker = new BackgroundWorker();
    worker.DoWork += (s, args) =>
    {
        // Here you perform the operation and report progress:
        int percentProgress = ...
        string currentFilename = ...
        ((BackgroundWorker)s).ReportProgress(percentProgress, currentFilename);
        // Remark: Don't modify the GUI here because this runs on a different thread
    };
    worker.ProgressChanged += (s, args) =>
    {
        var currentFilename = (string)args.UserState;
        // TODO: show the current filename somewhere on the UI and update progress
        progressBar1.Value = args.ProgressPercentage;
    };
    worker.RunWorkerCompleted += (s, args) =>
    {
        // Remark: This runs when the DoWork method completes or throws an exception
        // If args.Error != null report to user that something went wrong
        progressBar1.Value = 0;
    };
    worker.RunWorkerAsync();
}
Darin Dimitrov
Thanks. Good remarks about the GUI, I got the exception ... :) Instead of percentProgress, I'd like have the file name in treatment and why not the percentage ?
Kris-I
You could use `BackgroundWorker.ReportProgress(int, object)` where the second argument is a custom user state object that you could use in the `ProgressChanged` callback through `args.UserState`.
Darin Dimitrov
I've updated my answer to take this into account.
Darin Dimitrov
In my business class, in the loop, I set a property with the current file in progress. But I never pass in the "ProgressChanged"
Kris-I
You will have to show your code.
Darin Dimitrov
Darin, I added the code in the question
Kris-I
@Kris, the `ProgressChanged` callback is called every time you invoke the `ReportProgress` method, so you will need to pass a delegate to your business object which will point to the ReportProgress method and which will be called periodically.
Darin Dimitrov