views:

1344

answers:

3

Hi guys,

Below is a method that I want to ship off into a background worker but I am struggling how to do it based on how created my method. As you can it doesn't return anything which is ok but it expects a directoryInfo object everytime it is recalled.

    private void getSizeForTargetDirectory(DirectoryInfo dtar)
    { 
        // generate a collection of objects. files comes first and then directories.

        foreach (Object item in collection )
        {
            if (item == file)
            {
               track the size of the files as you encounter.
            }
            else if (item == directory)
            {
                // found a new directory, recall the method. !!!
            }
        }
    }

This is my first time using a background worker so I'm a little stuck, I tried implementing something thanks to the help found here but got stuck when I realised my method was recursive.

http://stackoverflow.com/questions/1194620/c-newbie-show-progress-during-a-loop-wpf

I implemented a doWork event handler method but noticed that i needed to somehow recall the method if I had more files and folders to process on lower sub levels.

I have a simple button click event handler that calls my 'getSizeForTargetDirectory()' method when the current selected node is a directory.

 private void retrieveInfoButton_Click(object sender, EventArgs e)
    {
        // check to see if the path is valid
        // reset the labels and textfields.
        string fullPath = treeDrives.SelectedNode.FullPath;
        string sNodesName = treeDrives.SelectedNode.Text;

        if (directory) // Enter here if its a directory.
        {
            string parentPath = treeDrives.SelectedNode.Parent.FullPath;
            DirectoryInfo[] dirArray = populateFoldersArray(parentPath);

            for (int i = 0; i < dirArray.Length; i++)
            {
                if (dirArray[i].Name == sNodesName)
                {
                    getSizeForTargetDirectory(dirArray[i]);

                    // do work !

Hopefully that explains what I am trying to do and how I am doing it. Question is how can i use the report progress feature of the background worker class when the bulk of the work I am trying to ship is coming from a recursive method.

Through early testing I noticed that my getSize method was incredibly efficient after a few tweaks and reported size information for the current supplied folder very quickley but then again I use quite a powerful dev machine so this may not be true for all users.

Thanks For Reading, Hope someone can help !!!

+2  A: 

I think it is much simpler to use the built-in methods on either Directory or DirectoryInfo to obtain all directories, or files, using the recursive search option:

public partial class Form1 : Form
{
    private Action<float> updateProgMethod;

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        updateProgMethod = UpdateProgress;
    }

    private void GetDirectorySizeAsync(string path)
    {
        backgroundWorker.RunWorkerAsync(path);
    }

    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        DirectoryInfo di = new DirectoryInfo((string)e.Argument);
        di.GetTotalSize(ProgressCallback);
    }

    // Takes callbacks from the GetTotalSize() method
    private void ProgressCallback(float p)
    {
        // Invokes update progress bar on GUI thread:
        this.BeginInvoke(updateProgMethod, new object[] { p });
    }

    // Actually updates the progress bar:
    private void UpdateProgress(float p)
    {
        progressBar.Value = (int)(p * (progressBar.Maximum - progressBar.Minimum)) + progressBar.Minimum;
    }
}

public static class IOExtensions
{
    public static long GetTotalSize(this DirectoryInfo directory, Action<float> progressCallback)
    {
        FileInfo[] files = directory.GetFiles("*.*", SearchOption.AllDirectories);
        long sum = 0;
        int countDown = 0;
        for (int i = 0; i < files.Length; i++)
        {
            sum += files[i].Length;
            countDown--;
            if (progressCallback != null && countDown <= 0)
            {
                countDown = 100;
                progressCallback((float)i / files.Length);
            }
        }
        return sum;
    }
}

It's hard to guess progress without knowing the number of files or folders first!

EDIT: I've improved the code a little.

Cecil Has a Name
Hello cecil ...question?This is an interesting bit of code ... does this mean that from a given directoryInfo object I can use search options to return all files under a given directory? Either case, Ii am going to have to try this out as this changes everything !!!
IbrarMumtaz
Yes. And it does not increase the running time if you are going to enumerate each and every file anyway.
Cecil Has a Name
+1  A: 

If, when you call a method, you don't know how long the method is going to take or how many discrete steps are going to be involved, then there is no way to display a progress bar while the method is executing.

In my opinion, the purpose of a progress bar is not to give reliable information about when a task is going to be completed. Rather, the purpose is to keep the user from freaking out and cancelling the whole operation because they think your program has locked up and isn't doing anything at all.

Since you're iterating through directories and sub-directories, a simpler approach here might be to just display the current directory in a Label. This would give the user a relaxing sense that things are happening, and if the directories are all ordered alphabetically, they can even gauge for themselves the overall progress of the operation.

MusiGenesis
Don't forget to add one of those cool spinny wheel things!
Pondidum
@Andy: I always liked what Netscape used to do - they had a progress bar that advanced to the right, and when it got there it reversed and advanced to the left, and so on ad infinitum.
MusiGenesis
That makes alot of sense I'm pretty still new to C# coding so the first reply scared me a little. Although i like the idea updaing a simple label. Quite a few options have suddenly come to mind. TY
IbrarMumtaz
A: 

I would report how far you have gotten since you don't know the goal until you get there. I would do it once per invocation. Perhaps # of files and # of directories seen so far.

stonemetal
My original method does track the number of files and directories seen so far ... reporting how far I have gotten seems to be quite a plausable avenue to explore. TIA
IbrarMumtaz