#c# #backgroundworker
#c# #BackgroundWorker
Вопрос:
Я пытаюсь обновить индикатор выполнения в основной форме, поскольку работа выполняется в другом классе. Например:
private void transfer_Click(object sender, EventArgs e)
{
Guid aspnetUserId = Guid.Parse(System.Configuration.ConfigurationSettings.AppSettings["ASPNetUserID"]);
WC1toWC2Transfer transfer = new WC1toWC2Transfer(aspnetUserId);
backgroundWorker1.RunWorkerAsync(transfer);
}
И затем в фоновом методе фактически вызывается метод:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
WC1toWC2Transfer transfer = e.Argument as WC1toWC2Transfer;
transfer.WC1ToWC2EmployerTransfer(log, wc1ConnStr, wc2ConnStr, progressBar1);
}
В методе WC1ToWC2EmployerTransfer я устанавливаю максимум индикатора выполнения и обновляю значение каждый раз, когда что-то передается в базу данных в этом методе, но когда я делаю это, ничего не происходит. Внутри метода есть код, который запускает хранимую процедуру в базе данных, но как только он попадает в эту часть кода, он прекращает отладку, и мне приходится запускать процесс снова.
Я делаю здесь что-то не так? Нужно ли мне переписывать то, что у меня есть, чтобы фактические методы были в основной форме, а не в другом классе? Я младший разработчик (начал работать всего несколько месяцев назад), поэтому простите меня, если я делаю что-то явно неправильное или недостаточно хорошо объяснил это.
Любая помощь будет с благодарностью принята.
Комментарии:
1. Не уверен, о чем это, но вы определенно захотите устранить неполадки «это останавливает отладку». BackgroundWorker проглатывает исключения и передает их обработчику событий RunWorkerCompleted со свойством e.Error . Что-то, что вы не хотите игнорировать. Лучший способ не игнорировать это с помощью Debug Exceptions, установите флажок для исключений CLR.
Ответ №1:
Вы не можете изменить пользовательский интерфейс, если вы не находитесь в основном потоке, которым вы, фоновый рабочий, не будете.
Что вам нужно сделать, это создать обработчик событий в основной форме для обработки события ProgressChanged backgroundworker.
например
// this method should be in your main form.
private void backgroundworker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// update your progress bar here.
}
В вашем фоновом рабочем вы вызываете метод ReportProgress, который запускает событие ProgressChanged.
Здесь есть хороший пример.
Ответ №2:
Я думаю, причина в том, что вы получаете an IllegalCrossThreadException
, потому что вы пытаетесь получить доступ к элементу управления из другого потока, чем он был создан. BackgroundWorker
Предоставляет метод ReportProgress и событие ProgressChanged, которое обычно используется для такого обновления и которое будет выполняться в потоке пользовательского интерфейса. При доступе к progressbar из другого потока, отличного от потока пользовательского интерфейса, сделайте это следующим образом:
if(progressBar1.InvokeRequired) {
progressBar1.Invoke(new MethodInvoker(delegate { progressBar1.Maximum = someValue; }));
}
В качестве примечания: передача панели прогресса вашему рабочему классу — не очень хороший дизайн. Форма может закрыться, она может быть удалена, и рабочий ничего об этом не узнает, в конечном итоге произойдет сбой, ObjectDisposedException
который, вероятно, не будет обнаружен. Кроме того, вы ставите работника в зависимость от System.Windows.Forms
того, когда в этом, вероятно, нет необходимости. Вместо этого пусть ваш работник сообщает о ходе выполнения события и передает это на вашу панель выполнения из класса, который создал работника.
Комментарии:
1. Кроме того, если вам интересно, Progression (отказ от ответственности: я написал это) — это очень простая библиотека для вычисления прогресса, которая позволяет вашим рабочим методам корректно сообщать о прогрессе, ничего не зная об пользовательском интерфейсе. Либо пользовательский интерфейс подписывается на потокобезопасные события, либо
BackgroundWorker
может подписаться на события и сообщать о них.