Использование фонового работника - обновление ProgressBar о прогрессе рекурсивного метода - PullRequest
2 голосов
/ 26 августа 2009

Ниже приведен метод, который я хочу отправить в фоновый рабочий, но я изо всех сил пытаюсь сделать это, основываясь на том, как был создан мой метод. Как вы можете, он не возвращает ничего, что в порядке, но он ожидает объект directoryInfo при каждом вызове.

    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. !!!
            }
        }
    }

Это мой первый раз, когда я работаю в фоновом режиме, поэтому я немного застрял, я попытался реализовать что-то благодаря помощи, найденной здесь, но застрял, когда понял, что мой метод рекурсивен.

Как отобразить прогресс во время цикла занятости?

Я реализовал метод обработчика событий doWork, но заметил, что мне нужно каким-то образом вызвать метод, если у меня будет больше файлов и папок для обработки на более низких подуровнях.

У меня есть простой обработчик события нажатия кнопки, который вызывает мой метод getSizeForTargetDirectory (), когда текущий выбранный узел является каталогом.

 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 !

Надеюсь, это объясняет, что я пытаюсь сделать и как я это делаю. Вопрос в том, как я могу использовать функцию выполнения отчетов в фоновом рабочем классе, когда основная часть работы, которую я пытаюсь выполнить, исходит из рекурсивного метода.

В ходе раннего тестирования я заметил, что мой метод getSize был невероятно эффективен после нескольких настроек и сообщил о размере информации для текущей поставляемой папки очень быстро, но с другой стороны, я использую довольно мощную машину разработчика, так что это может быть не так для всех пользователей.

Спасибо за чтение, надеюсь, кто-то может помочь !!!

Ответы [ 3 ]

3 голосов
/ 26 августа 2009

Я думаю, что гораздо проще использовать встроенные методы в Directory или DirectoryInfo для получения всех каталогов или файлов, используя опцию рекурсивного поиска:

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;
    }
}

Трудно угадать прогресс, не зная сначала количества файлов или папок!

РЕДАКТИРОВАТЬ: я немного улучшил код.

2 голосов
/ 26 августа 2009

Если, когда вы вызываете метод, вы не знаете, как долго будет выполняться метод или сколько отдельных шагов будет задействовано, тогда нет способа отобразить индикатор выполнения во время выполнения метода. .

По моему мнению, цель индикатора выполнения - не предоставлять достоверную информацию о том, когда задача будет завершена. Скорее цель состоит в том, чтобы не дать пользователю сойти с ума и отменить всю операцию, потому что он думает, что ваша программа заблокирована и ничего не делает.

Поскольку вы перебираете каталоги и подкаталоги, более простой подход здесь может заключаться в том, чтобы просто отобразить текущий каталог в метке. Это дало бы пользователю расслабленное ощущение, что что-то происходит, и если все каталоги упорядочены в алфавитном порядке, они могут даже сами оценить общий ход операции.

0 голосов
/ 26 августа 2009

Я бы сообщил, как далеко вы продвинулись, поскольку вы не знаете цели, пока не доберетесь туда. Я бы сделал это один раз за вызов. Возможно, количество файлов и количество каталогов, замеченных до сих пор.

...