Использование фонового рабочего — обновление ProgressBar в ходе выполнения рекурсивного метода

Ниже приведен метод, который я хочу отправить в фоновый рабочий процесс, но я изо всех сил пытаюсь сделать это, основываясь на том, как создан мой метод. Как вы можете, он ничего не возвращает, что нормально, но он ожидает объект 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 был невероятно эффективным после нескольких настроек и очень быстро сообщал информацию о размере текущей предоставленной папки, но опять же, я использую довольно мощную машину для разработки, поэтому это может быть верно не для всех пользователей.

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


person IbrarMumtaz    schedule 26.08.2009    source источник


Ответы (3)


Я думаю, что гораздо проще использовать встроенные методы для 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;
    }
}

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

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

person Cecil Has a Name    schedule 26.08.2009
comment
Привет, Сесил ... вопрос? Это интересный фрагмент кода ... означает ли это, что из данного объекта directoryInfo я могу использовать параметры поиска для возврата всех файлов в данном каталоге? В любом случае, мне придется попробовать это, так как это все меняет !!! - person IbrarMumtaz; 27.08.2009
comment
да. И это не увеличивает время выполнения, если вы все равно собираетесь перечислять каждый файл. - person Cecil Has a Name; 27.08.2009
comment
Очень полезно. Реализовано в WPF MVVM и прекрасно работает. - person Rakshit Bakshi; 29.05.2012

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

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

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

person MusiGenesis    schedule 26.08.2009
comment
@Andy: Мне всегда нравилось то, что раньше делал Netscape - у них был индикатор выполнения, который продвигался вправо, а когда он туда попадал, он переворачивался и продвигался влево, и так до бесконечности. - person MusiGenesis; 26.08.2009
comment
Это имеет большой смысл. Я все еще новичок в программировании на C #, поэтому первый ответ меня немного напугал. Хотя мне нравится идея обновить простую этикетку. В голову сразу пришло несколько вариантов. ТЮ - person IbrarMumtaz; 26.08.2009

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

person stonemetal    schedule 26.08.2009
comment
Мой первоначальный метод действительно отслеживает количество файлов и каталогов, просмотренных до сих пор ... отчет о том, как далеко я продвинулся, кажется вполне правдоподобным путем для изучения. ТИА - person IbrarMumtaz; 26.08.2009