Sam wrote:
Branco,
First, thank you so much for taking the time to help me, I really
appreaciate that.
I've read your post several times, it took me some time to figure out
what's going on!
I've tried to implement your approach in my sample and I've come across
a number of issues:
The first one is that in Progress_FormClosing, the test :
If Worker.IsBusy Then
fails as Worker is always NULL at that point, and I don't know why.
The second issue I have is that the progressform doesn't show at all.
I've uploaded my sample, maybe you can have a quick look at it. It is
rather close to the code you provided me with, so it should be easy for
you to understand it. I'd be very grateful if you could tell me where
I'm doing wrong in trying to use your code.
http://graphicsxp.free.fr/WindowsApplication11.zip
With regards,
Sam,
First, sorry for the confusion. My last two posts suggest two sepparate
solutions, but it didn't become clear that the last post was
introducing a new approach, not complementing the previous one.
I noticed the confusion by checking your implementation, where both
solutions are attempted... :-D
Summarizing:
Solution 1, with multithreading:
You implement a base AsyncWork class which must be inherited by the
actual workers. The Progress form launches the work with a call to the
worker's Work method, just before going modal. This approach is more
complicated because of the issues related to multithreading (such as
the UI updating) and the extra classes, etc, but would give you a solid
framework that would Just Work (tm) as soon as you resolved these basic
issues. I'd use this solution if there's not much UI updating while
executing the concurrent work, or this UI updating can be modularized
in some way.
Solution 2, without multithreading
Every child form has a DoWork method (just as you were implementing).
As in the previous solution, you rely in the Progress form to start the
work, but since this doesn't use multithreading, you must take
additional steps such as using the progress form's Activate event (see
the code bellow). Likewise, the child form's DoWork method must rely in
Application.DoEvents to keep the UI updated. This approach seems more
ad hoc, but I'd dare to use it if most of the work consisted of UI
updates that could not be dettached from the actual background work,
which seems to be your case.
In your sample both solutions are half way implemented, I guess that's
why you had problems...
To implement Solution 2, which seems to adapt more seemlessly to your
original approach, this is what your classes would look like (notice
that I changed the order of the tests in the progress form Activate
event -- :-P ):
'In the progress form
Public Shared ReadOnly DefaultInstance As New frmProgress
Public Delegate Sub DoWorkDelegate()
Private mDone As Boolean
Private mWorker As DoWorkDelegate
Public Sub Progress_Activate( _
ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles Me.Activated
If Not mWorker Is Nothing Then
If Not mDone Then
mDone = True
Application.DoEvents()
mWorker()
Close()
End If
End If
End Sub
Public Sub DoWork(ByVal Worker As DoWorkDelegate)
mDone = False
mWorker = Worker
ShowDialog()
End Sub
Public Sub UpdateProgress( _
ByVal Text As String, _
ByVal Percent As Integer)
ProgressBar1.Value = Percent
Label1.Text = Text
Label1.Refresh()
End Sub
Public Sub InitProgress( _
ByVal Text As String, _
ByVal Percent As Integer)
ProgressBar1.Minimum = 0
ProgressBar1.Value = 0
ProgressBar1.Maximum = Percent
Label1.Text = Text
Label1.Refresh()
End Sub
Also, replace the child's form code with this sample:
'In Child Form
Sub DoWork()
frmProgress.DefaultInstance.InitProgress("", 100)
For i As Integer = 0 To 100
frmProgress.DefaultInstance.UpdateProgress(i.ToStr ing & "%", i)
Label1.Text = i.ToString
Application.DoEvents()
Next
Dim dt As String() = {"test", "test1", "test2"}
DataGrid2.DataSource = dt
TabControl1.SelectedTab = TabPage2
Application.DoEvents()
End Sub
Private Sub Form1_Load( _
ByVal sender As Object, _
ByVal e As System.EventArgs _
) Handles MyBase.Load
Show()
Dim Work As frmProgress.DoWorkDelegate
Work = AddressOf DoWork
frmProgress.DefaultInstance.DoWork(Work)
End Sub
Private Sub Button1_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs _
) Handles Button1.Click
Dim Work As frmProgress.DoWorkDelegate
Work = AddressOf DoWork
frmProgress.DefaultInstance.DoWork(Work)
End Sub
Finally, disable the TopMost property of the progress form (I don't
know why, but it was preventing the form from showing).
HTH.
Regards,
Branco.