VB.NET прогрессбар backgroundworker

когда мое приложение запускается, и оно только что было обновлено, я делаю обновление локальной базы данных (sqlite).

Это так: Пользователь запускает мое приложение, а затем я запускаю процесс обновления. Во время этого процесса обновления я показываю форму, которая имеет непрерывный progressbar. Эта форма закрывается, когда процесс обновления завершен, и пользователь может начать использовать мое приложение.

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

в моей старой версии VB6 я использовал ActiveX-Exe, который имеет форму 1 и показывает progressbar. Это был мой "фоновый работник".

Я не уверен, что могу использовать тот же подход в VB.NET.

Я видел только примеры, которые затем выполняют работу в фоновом работнике, но я не видел никаких примеров, когда сам progressbar был фоновым работником.

обновление базы данных должно быть заблокировано, пользователь не может использовать мое приложение до обновление базы данных выполнено. Это означает, что только progressbar должен "выйти из процесса", но не обновление.

большое спасибо!

6 ответов


сначала прочтите это: использование приложения.Функция doevents()

таким образом, после прочтения вышеуказанного ответа вы никогда больше не будете использовать DoEvents, и без DoEvents (и/или аннулирования ProgressBar, чтобы его событие Paint сработало) "progressbar не будет анимироваться, так как процесс обновления настолько интенсивен"

следовательно, комментарий Ктулху - " вы можете сделать диалог с progressbar, сделать этот диалог модальным и выполнить свой db-материал на backgroundworker." быть одним из лучших путей продвижения вперед.

Я перевел реализацию c# этого, что я использую, вы должны быть в состоянии бросить его прямо.

это форма ProgressBar:

Public Partial Class ThinkingProgressBar
    Inherits Form
    Private startTime As System.DateTime = DateTime.Now
    Public Sub New()
        InitializeComponent()
    End Sub

    Private Sub lblClose_LinkClicked(sender As Object, e As LinkLabelLinkClickedEventArgs)
        Me.Tag = "Cancelled"
        Me.Hide()
    End Sub

    Public Sub SetThinkingBar(ByVal switchedOn As Boolean)
        If switchedOn Then
            lblTime.Text = "0:00:00"
            startTime = DateTime.Now
            Timer1.Enabled = True
            Timer1.Start()
        Else
            Timer1.Enabled = False
            Timer1.Stop()
        End If
    End Sub

    Private Sub timer1_Tick(sender As Object, e As EventArgs)
        Dim diff As New TimeSpan()
        diff = DateTime.Now.Subtract(startTime)
        lblTime.Text = diff.Hours & ":" & diff.Minutes.ToString("00") & ":" & diff.Seconds.ToString("00")
        lblTime.Invalidate()
    End Sub
End Class

перетащите элемент управления BackgroundWorker в форму, вот фоновые рабочие события:

Private Sub backgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    e.Result = e.Argument
    'DirectCast(e.Result, ThinkingProgressBar).SetThinkingBar(True) 
    'DO LONG OPERATION HERE

End Sub

Private Sub backgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
    Dim dlg As ThinkingProgressBar = TryCast(e.Result, ThinkingProgressBar)
    If IsNothing(dlg) = False Then
        dlg.SetThinkingBar(False)
        dlg.Close()
    End If
End Sub

и вот вызывающий код, когда ваше приложение запускается и выполняет обновление:

Dim dlg As New ThinkingProgressBar()
dlg.SetThinkingBar(True)
BackgroundWorker1.RunWorkerAsync(dlg)
dlg.ShowDialog()
If IsNothing(dlg.Tag) = False AndAlso dlg.Tag.ToString() = "Cancelled" Then
    Return
End If

несколько вещей, вы можете предотвратить пользователя от Отмена (т. е. lblClose_LinkClicked) и положить в защитное/защитное программирование для обработки случаев, когда пользователь убивает процесс или выключает компьютер во время обновления.

и ProgressBar на самом деле анимированный gif - и это будет соответствовать вашему использованию, потому что оценка времени, необходимого для обновления базы данных, очень трудно предсказать:

enter image description here


из ваших требований, мне кажется, что вы ищете:

Application.DoAction()

Я испытал в приложении, что возникла необходимость загрузить 2000 до 3000 элементов, связанных с деталями из xml, и реализованный процесс читал элементы один за другим, который зависает процесс. Использование вышеуказанной строки в цикле решило мою проблему. Пользовательский интерфейс не зависал, и пользователь мог работать с другими формами. Это появилось progressbar is now as background process (до некоторой степени) для меня.

надеюсь, что это помогает!


Я понимаю ваше желание сделать progressbar фоновым потоком, но я совершенно уверен, что вы не сможете этого сделать. Поскольку вы хотите обновить визуальные компоненты приложения, пользовательский интерфейс должен быть основным потоком. Достаточно легко отключить все элементы управления в форме, включая пункты меню.

позвольте мне предложить этот процесс:

  1. покажите свою форму с упомянутой progressbar.

  2. Если вы показываете любые другие формы, отключаете все дочерние элементы управления, которые находятся непосредственно в форме. В зависимости от элемента управления Вам может потребоваться пройти через его дочерние элементы управления, чтобы отключить их.

  3. в коде, который выполняет обновление базы данных, обновите значение progressbar до значения, которое вы хотите. После обновления значения вызовите метод обновления progressbar. Это заставит progressbar правильно рисовать.

  4. после завершения обновления, скрыть progressbar, повторно включить все элементы управления на всех формах, которые вы отключили.

Это даст вам внешний вид progressbar, который работает в фоновом потоке, все еще давая вашему приложению блокировку основного потока по желанию.


это не проверено, но я помню, что делал что-то вроде этого, чтобы передать информацию BGW. Который обновит содержимое фонового рабочего.

сначала создайте класс (т. е. ProgExample) со следующими переменными и поместите его как глобальный объект.

Dim ProgValue as Integer;
Dim ProgMax as Integer;

затем передайте класс фоновому работнику.

BackgroundWorker1.RunWorkerAsync(_ProgExample)

прочитайте его и держите его внутри:

Dim BGWProgExample as ProgExample = DirectCast(e.Argument, ProgExample), 

в фоновом режиме работник сделать что-то следующий:

BGWProgressBar.Maximum = BGWProgExample.ProgMax
while BGWProgExample.ProgValue <> BGWProgExample.ProgMax
BGWProgressBar.Value = BGWProgExample.ProgValue 

поэтому, когда вы что-то сделали, просто обновите _ProgExample.Прогвалю. Не пытайтесь сделать это без класса, просто передав ProgValue в качестве аргумента. Это означает, что вы отправляете копию ProgValue в текущем состоянии, и она не изменится, если вы обновите ProgValue. И если это ничего не делает, попробуйте приложение.DoEvents и / или приложение.DoAction вместе с этим.


может быть, я не понимаю вопрос, но разве это не очень просто?

For i = ProgressBar1.Minimum To ProgressBar1.Maximum
        ProgressBar1.Value = i
        ProgressBar1.Update()
        System.Threading.Thread.Sleep(25)
    Next

" обновление " Progressbar делает трюк. Ваш код " блокирует "(хотя я не вижу, почему желательно иметь" приложение не respondig"), но Progressbar получает обновление d.

BTW: для Windows Vista / 7 (progressbar animation) вы можете проверить это:ProgressBar медленно в Windows Forms


вы можете вызвать событие в фоновом работнике, а затем обновить индикатор выполнения в потоке пользовательского интерфейса. Вы можете вызывать события в своем классе и обрабатывать их в форме. Когда они будут подняты, вы можете вызвать reportprogress () на фоновом работнике.

дополнительная информация:

выполнение длительных изменений пользовательского интерфейса без блокировки основного потока