Приложение 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, а не пытаться выполнить два вызова.

Другие вопросы по тегам