VB.NET progressbar backgroundworker

匿名 (未验证) 提交于 2019-12-03 02:23:02

问题:

When my application starts, and it has just been upgraded, I am doing a local database update (sqlite).

It is like that: The user starts my app, and then I start the upgrade process. During this upgrade process I am showing a form that has a continuous progressbar. This form closes when the upgrade process is done and the user can then start using my application.

But the progressbar won't animate since the upgrade process is so intensive.

In my old VB6 version I used an ActiveX-Exe that has 1 form and shows a progressbar. This was my "background worker".

I am not sure if I can use the same approach in VB.NET.

I have only seen examples that then do the work in the background worker, but I have not seen any examples where the progressbar itself was the background worker.

The database upgrade needs to be blocking, the user may NOT use my application before the database upgrade was done. This means that only the progressbar should "out of process", but not the upgrading.

Thank you very much!

回答1:

First read this: Use of Application.DoEvents()

So after reading the above answer you will never using DoEvents ever again, and without the DoEvents (and/or Invalidating the ProgressBar so its Paint event will fire) the "progressbar won't animate since the upgrade process is so intensive"

Hence Cthulhu's comment - "You can make a dialog with a progressbar, make that dialog modal and execute your db-stuff on a backgroundworker." is one of the best ways forward.

I have translated a C# implementation of this that I use, you should be able to drop it straight in.

This is the ProgressBar Form:

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 

Drag/Drop a BackgroundWorker control onto the form, here are the background worker events:

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 

And here is the calling code for when your application starts and does the upgrading:

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 

A couple of things, you may prevent the user from Cancelling (ie lblClose_LinkClicked) and put in protective/defensive programming to handle cases where the user kills the process or turns off their PC during the upgrade.

And the ProgressBar is actually an animated gif - and this will suit your usage because estimating the time it takes to update a database is very hard to predict:



回答2:

From your requirements it seems to me that you are looking for:

Application.DoAction() 

I have experienced in an application that there was a need to load 2000 to 3000 items related detail from xml and the implemented process was reading items one by one which hangs up the process. Using the above line in the loop resolved my issue. The UI did not hang-up and user was able to work on other forms. This appeared progressbar is now as background process (upto some extent) to me.

Hope it helps!



回答3:

I understand your desire to make the progressbar the background thread, but I am fairly certain that you will not be able to do this. Because you want to update the visual components of your application, the UI needs to be the primary thread. It is easy enough to disable all of the controls on a form, including menu items.

Let me suggest this process:

  1. Show your form with the progressbar mentioned.

  2. If you show any other forms, disable all child controls that are directly on the form. Depending on the control, you may have to walk through its child controls to disable them.

  3. In the code that performs the database update, update the progressbar's value to what ever value you desire. Upon updating the value, call the progressbar's refresh method. This will force the progressbar to paint correctly.

  4. Once your update completes, hide the progressbar, re-enable all of the controls on all of the forms that you disabled.

This will give you the appearance of a progressbar that is running in the background thread while still giving your application the blocking of the main thread as desired.



回答4:

This is not tested but I recall doing something like this to feed information to a BGW. Which would update the background worker contents.

First create a class(i.e. ProgExample) with the following variables and put it as a global object.

Dim ProgValue as Integer; Dim ProgMax as Integer; 

Then feed the class to the background worker.

BackgroundWorker1.RunWorkerAsync(_ProgExample) 

Read it and hold it inside:

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

In background worker do something the following:

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

So when you've done something just update _ProgExample.ProgValue. Don't try to do this without a class by just passing ProgValue as argument. That would mean that you send a copy of ProgValue in its current state and it would not change if you were to update ProgValue. And if this doesn't do anything try the Application.DoEvents and/or Application.DoAction together with this.



回答5:

Maybe I dont understand the question, but isnt it really simple?

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

The "Update" of Progressbar does the trick. Your code "blocks" (though I can not see, why it's desirable to have "application not respondig"), but the Progressbar gets updated.

BTW: For Windows Vista/7 (progressbar animation) you might check this: ProgressBar is slow in Windows Forms



回答6:

You can raise an event in the background worker and then update the progress bar on the UI thread. You can raise events in your class and handle them in the form. When they are raised, you can call reportprogress() on the background worker.

some more info:

Performing long running UI changes without blocking the main thread



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!