Фоновый рабочий - отчет о прогрессе с массивом строк - PullRequest
9 голосов
/ 28 марта 2011

Мне нужно возвращать несколько значений STRING от моего фонового работника в каждом цикле, поэтому я попытался использовать второй параметр ReportProgress в качестве строкового массива.Пример кода:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    string[] workerResult = new string[2];
    for (int i=0; i<someNumber; i++)
    {
        //do some heavy calculating
        workerResult[0] = "this string";
        workerResult[1] = "some other string";
        backgroundWorker1.ReportProgress(i, workerResult) // also tried workerResult[] and [2]
    }
}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    string[] results = (string[])e.UserState;

    MessageBox.Show(results[0]); // line of error
    MessageBox.Show(results[1]); // line of error
}

Компилируется, но во время выполнения в момент, когда я пытаюсь получить доступ к возвращенной строке Userstate, я получаю ошибку: «Ссылка на объект не установлена ​​на экземпляр объекта.»

Мне кажется, что что-то не так при передаче параметра массива делегату ProgressChanged или в методе ProgressChanged при попытке установить значения массива результатов.

Ответы [ 3 ]

18 голосов
/ 28 марта 2011

Ваш фрагмент кода не может воспроизвести проблему. Стандартная ошибка - вызвать ReportProgress () и затем продолжить модификацию объекта. Для запуска обработчика события требуется некоторое время, он увидит измененный объект, а не исходный. Этого можно избежать, просто создав новый объект, чтобы обработчик событий всегда работал с оригиналом. Как это:

        //do some heavy calculating
        for (int i = 0; i < 2; ++i) {
            string[] workerResult = new string[2];
            workerResult[0] = "this string";
            workerResult[1] = "some other string";
            backgroundWorker1.ReportProgress(i, workerResult);
        }

Обратите внимание, как оператор создания массива перемещается внутри цикла.

8 голосов
/ 28 марта 2011

когда вы создаете экземпляр BackgroundWorker, вам нужно установить для свойства reportprogress значение true:

worker = new BackgroundWorker { WorkerReportsProgress = true };

В методе do work вам просто понадобится:

 worker.ReportProgress(10, "Message");

Тогда что-то вроде этого, чтобы поймать прогресс:

private void WorkerProgressChanged(object sender, ProgressChangedEventArgs e) {
            if (e.UserState != null) {
                MessageBox.Show(e.UserState);
            }
        }
0 голосов
/ 16 сентября 2011

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

bool progressed;

backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
string[] workerResult = new string[2];
for (int i = 0; i < 2; ++i) {
    progressed=true;

    workerResult[0] = "this string";
    workerResult[1] = "some other string";
    backgroundWorker1.ReportProgress(i, workerResult);
    while (progressed)
    {
       //you can add a thread sleep 
    }
}


void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
     progressed = false;
}
...