Фоновый рабочий обновляет ProgressBar частично или не все, затем бомбит - PullRequest
1 голос
/ 11 ноября 2009

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

Смотрите здесь:

Первая попытка у фонового работника.

В результате мне удалось заставить его работать, но в некоторых случаях он частично заполняется, а иногда нет вообще. Выход со следующим исключением?

TargetInvocationException был не обработан .. Исключение было сгенерировано целью вызова.

Бомбардировка этой строки кода в моей программе.

[MTAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new MainForm()); <-- Exception raised at this line !!!
}

Он также был выделен зеленым цветом, чего я никогда раньше не видел. Я также попытался изменить атрибут также с STA на MTA. Если это что-то или что-то не так ... тогда, пожалуйста, расскажите. Поскольку я склонен полагать, что это должно быть возглавлено [MTAThread].

Мое приложение не вызывает ошибку, если я не сообщаю о прогрессе, но когда я делаю выше, всегда гарантируется, что произойдет. Я очистил свой обработчик событий DoWork, чтобы он не вызывал межпотоковые вызовы для потока, в котором определен какой-либо элемент управления, т. Е. Метка. Я удалил их, даже если они работают, хотя Albabari.com сказал мне, что они не должны работать и не должны быть там. Так что я удалил и застрял с этим ... Это намного проще, чище, аккуратнее и поточнее с показанной важной частью.

private void worker_DoWork(object sender, DoWorkEventArgs e)
{
    ...

    for (int i = 0; i < allFiles.Length; i++)
    {
        localSize += allFiles[i].Length;
        // a label used to say   what file is being processed.
        //toolStripStatusLabel.Text = allFiles[i].Name; 
        localFiles++;                
        worker.ReportProgress((100 * i) / allFiles.Length);
    }

    ...
}

private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // this event handler is also implemented in my application.
}

private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    fileRetrievalProgressBar.Value = Math.Min(e.ProgressPercentage, 100);
}

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

Имеет ли моя проблема что-то, связанное с тем, как я называю мой индикатор выполнения, или с тем, чтобы сделать и 1027 *, или BeginInvoke() ... что-то похожее на эти строки. Я просто догадываюсь, но фоновый работник не сделает это автоматически для вас. Или это автоматически подразумевается и что-то, на что я должен ответить, поскольку я не знаю, когда это может произойти. Так что мне придется делать что-то вроде:

this.Invoke() или this.BeginInvoke()

При наведении указателя мыши на обе части кода открывается интересная подсказка, которая имеет большой смысл, но я изо всех сил пытаюсь реализовать. Как я считаю, анонимный метод используется? Я использую ниже мой пример для предыдущего заявления:

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

Благодаря парню под названием «У Сесила есть имя»!

Так и должно быть. С нетерпением жду некоторых ответов на эту мою маленькую проблему.

Ответы [ 3 ]

3 голосов
/ 11 ноября 2009

Прежде всего, вы на самом деле можете обновить эту метку состояния потокобезопасным способом, используя событие ProgressChanged, которое вы уже используете; BackgroundWorker.ReportProgress имеет перегрузку, которая принимает параметр object для передачи дополнительной информации именно для этой цели.

Во-вторых, , если , проблема в том, что вы пытаетесь установить значение индикатора выполнения выше максимального, возможно, ваше жестко заданное значение 100 не соответствует значению * 1010 индикатора выполнения * свойство (хотя это кажется маловероятным, поскольку 100 является значением по умолчанию, я считаю).

Так что мои предлагаемые изменения в вашем коде будут:

private void worker_DoWork(object sender, DoWorkEventArgs e)
{
    for (int i = 0; i < allFiles.Length; i++)
    {
        localSize += allFiles[i].Length;
        localFiles++;

        // this you can pass to ReportProgress
        string statusText = allFiles[i].Name;

        int progressPercentage = (100 * i) / allFiles.Length;
        worker.ReportProgress(progressPercentage, statusText);
    }
}

private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    // now that this is being done here, it is thread-safe
    string statusText = e.UserState as string;
    if (!string.IsNullOrEmpty(statusText))
    {
        toolStripStatusLabel.Text = statusText;
    }

    // your progress should be capped at the ProgressBar's Maximum,
    // rather than 100
    int progress = e.ProgressPercentage;
    int maxProgress = fileRetrievalProgressBar.Maximum;
    fileRetrievalProgressBar.Value = Math.Min(progress, maxProgress);
}
1 голос
/ 11 ноября 2009

Код, который вы разместили выше, выглядит хорошо (хотя вам не нужно использовать BeginInvoke() в обработчике событий ProgressChanged). Причина, по которой это выглядит как Application.Run(), вызывает исключение, потому что у вас нет других try / catch в стеке вызовов.

Исключением, которое вы перечисляете, является не сама возникающая проблема, а просто оболочка. Если вы посмотрите на InnerException сгенерированного исключения, оно должно дать вам больше информации о том, что происходит.

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

Исходя из внутреннего исключения, похоже, что значение, которое вы устанавливаете для индикатора выполнения, не находится между минимальным и максимальным значениями индикатора выполнения. Вы установили минимальное и максимальное значения и убедились, что все значения, установленные в индикаторе выполнения, находятся между ними?

0 голосов
/ 11 ноября 2009

В Visual Studio в меню отладки нажмите «Исключения ...». Установите флажок «Исключения общего времени выполнения» и запустите свой код. Таким образом, когда выдается исключение, процесс прерывается и выделяет линию зеленым цветом

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

...