Приложение VB.Net Winform, основанное на концепции BackgroundWorker Thread - проблема обновления пользовательского интерфейса
Команда,
Я создал приложение для Windows на VB.Net, которое загружает данные в базу данных и в основном обновляет два элемента управления:
1. Текстовое поле, которое постоянно обновляется с одной строкой для каждой загрузки записи базы данных.
2. Метка, которая отслеживает количество загруженных записей базы данных.
Я использовал концепцию потока BackgroundWorker, где метод bgwWorker_DoWork() потока содержит бизнес-логику для загрузки, а bgwWorker_ProgressChanged() обновляет 2 элемента управления пользовательского интерфейса в зависимости от загрузки.
Но проблема, с которой я сталкиваюсь, заключается в том, что я не получаю полных обновлений обоих элементов управления пользовательского интерфейса. Иногда поток обходит обновление текстового поля, а иногда и метки. Я мог бы решить эту проблему, добавив System.Threading.Thread.Sleep(25) перед каждым кодом обновления элемента управления пользовательского интерфейса. Это правильный способ решения проблемы? ИЛИ что-то мне не хватает?
Пожалуйста, предложите.
Ниже приведен код в обоих этих методах:
Private Sub bgwWorker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgwWorker.DoWork
.................
.................
'Updates database record related update in textbox
System.Threading.Thread.Sleep(25)
updater.eventName = "UpdateStatusBox"
updater.errorMessageToLog = String.Empty
updater.errorMessageToLog += GetErrorMessage(dataTable(rowNumber)("Name").ToString(), ExceptionData)
bgwWorker.ReportProgress(1, updater)
.................
.................
'Updates Status Count in LABEL
System.Threading.Thread.Sleep(25)
updater.eventName = "UpdateStatusBar"
updater.successCount = successCount.ToString()
updater.failureCount = failureCount.ToString()
bgwWorker.ReportProgress(2, updater)
End Sub
Private Sub bgwWorker_ProgressChanged(ByVal sender As System.Object, ByVal e As ProgressChangedEventArgs) Handles bgwWorker.ProgressChanged
Dim updater As UIUpdater = TryCast(e.UserState, UIUpdater)
..........................................
If updater.eventName = "UpdateStatusBar" Then
UpdateStatusBar(updater.successCount, updater.failureCount)
ElseIf updater.eventName = "UpdateStatusBox" Then
txtUpdates.Text = txtUpdates.Text & updater.errorMessageToLog
End If
.....................................
End Sub
2 ответа
Я почти уверен, что ваша проблема - это ваш пример UIUpdater
объект называется updater
, Этот объект, кажется, объявлен глобально и таким образом разделен между вызовами.
Пропустив немного кода, вот что у вас есть:
updater.eventName = "UpdateStatusBox"
bgwWorker.ReportProgress(1, updater)
updater.eventName = "UpdateStatusBar"
bgwWorker.ReportProgress(2, updater)
Хотя вы звоните ReportProgress()
линейно, это не уволит ProgressChanged
событие немедленно и не блокируется, пока этот метод не завершится. Это может привести к потере цели, если вы подумаете об этом.
Другими словами, у вас есть глобальный объект, для которого вы устанавливаете свойство. Затем вы говорите: "Когда у кого-то есть шанс, сделайте что-нибудь с этим". Затем вы изменяете свойство этого глобального объекта, и иногда это происходит до того, как "кто-то что-то сделал".
Решением является либо создание двух глобальных переменных, по одной для каждого возможного события, либо просто создание переменной экземпляра при необходимости. Я не уверен, что его поток безопасно использовать глобальную переменную, как вы, поэтому я бы рекомендовал просто создать переменную экземпляра. Фактически, государственный объект, который вы передаете ReportProgress
может быть просто строкой.
Я бы не использовал сон в вашем событии DoWork.
Вы пытались обновить элемент управления после его обновления? Каждый элемент управления имеет метод Refresh, который вызывает перерисовку. Это может привести к мерцанию.
Другой вариант - включить информацию, необходимую для обоих элементов управления (текстовое поле и метка), в один вызов ReportProgress, а не пытаться выполнить два вызова.