Приложение VB.Net Winform, основанное на концепции BackgroundWorker Thread - проблема обновления пользовательского интерфейса - PullRequest
1 голос
/ 26 января 2012

Team,
Я создал приложение для Windows на VB.Net, которое загружает данные в базу данных и в основном обновляет два элемента управления:
1. Текстовое поле, которое постоянно обновляется по одной строке на каждую запись базы данных.
2. Метка, которая отслеживает количество загруженных записей базы данных.

Я использовал BackgroundWorker thread концепцию, где метод 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 ]

4 голосов
/ 26 января 2012

Я почти уверен, что ваша проблема в вашем экземпляре UIUpdater объекта с именем updater.Похоже, этот объект объявлен глобально и, таким образом, распределяется между вызовами.

Пропуская немного кода, у вас есть следующее:

updater.eventName = "UpdateStatusBox"
bgwWorker.ReportProgress(1, updater)

updater.eventName = "UpdateStatusBar"
bgwWorker.ReportProgress(2, updater)

Хотя вы вызываете ReportProgress() линейно, этоне запускает ваше событие ProgressChanged немедленно и не блокируется, пока этот метод не завершится.Если вы подумаете об этом, это лишит смысла многопоточность.

Другими словами, у вас есть глобальный объект, для которого вы устанавливаете свойство.Затем вы говорите: «Когда у кого-то есть шанс, сделайте что-нибудь с этим».Затем вы изменяете свойство этого глобального объекта, и иногда это происходит до того, как произойдет "кто-то что-то сделал".

Решение состоит в том, чтобы создать две глобальные переменные,один для каждого возможного события или просто создать переменную экземпляра, когда это необходимо.Я не уверен, что его поток безопасно использовать глобальную переменную, как вы, поэтому я бы рекомендовал просто создать переменную экземпляра.Фактически, объект состояния, который вы передаете ReportProgress, может быть просто строкой.

0 голосов
/ 26 января 2012

Я бы НЕ использовал сон в вашем событии DoWork.

Вы пытались обновить элемент управления после его обновления? Каждый элемент управления имеет метод Refresh, который вызывает перерисовку. Это может привести к мерцанию.

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

...