using delegates and updating windows forms

B

Bill Angus

Hi all:

I have been playing around trying to get a progress bar to work. So far, I
have the progress bar updating visibly, but the rest of the dialog now looks
crappy. The rest of the dialog window badly needs a repaint, but it doesn't
get one until the routine finishes that the progress-bar is attached to.

I think part of the problem is that I don't understand the syntax for using
delegates and threads completely. Can any one point me to a web-article on
this topic, or perhaps tell me what I am doing wrong? I thought I had worked
the progress-bar more or less according to the VS2005 docs.
Example code follows
========================
' blah blah.... initial code

Delegate Sub UIDelegate()

Sub updateUI()
Me.ProgressBar1.Increment(1)
End Sub

Private Sub CreateBigCatalog() ' my time consuming routine
' Setup progress bar
Dim newDelegate As New UIDelegate(AddressOf updateUI)
Me.ProgressBar1.Value = 0

Me.ProgressBar1.Maximum = 1000

For Each title As DataRow In MyTitleTable.Rows

ProgressBar1.Invoke(newDelegate)

' ..... blah blah more time consuming code ....
next title

end sub
-----
What should I have done differently?

Thanks in advance and have a great day!

Bill Angus, MA
http://www.psychtest.com
 
B

Bill Angus

Oh yes... and the way I have it set up, the cancel button does not show up.... I wld like to have a working cancel button, but can't quite figure out what to do to make this happen.

Thanks in advance!

Bill Angus

Hi all:

I have been playing around trying to get a progress bar to work. So far, I
have the progress bar updating visibly, but the rest of the dialog now looks
crappy. The rest of the dialog window badly needs a repaint, but it doesn't
get one until the routine finishes that the progress-bar is attached to.

I think part of the problem is that I don't understand the syntax for using
delegates and threads completely. Can any one point me to a web-article on
this topic, or perhaps tell me what I am doing wrong? I thought I had worked
the progress-bar more or less according to the VS2005 docs.
Example code follows
========================
' blah blah.... initial code

Delegate Sub UIDelegate()

Sub updateUI()
Me.ProgressBar1.Increment(1)
End Sub

Private Sub CreateBigCatalog() ' my time consuming routine
' Setup progress bar
Dim newDelegate As New UIDelegate(AddressOf updateUI)
Me.ProgressBar1.Value = 0

Me.ProgressBar1.Maximum = 1000

For Each title As DataRow In MyTitleTable.Rows

ProgressBar1.Invoke(newDelegate)

' ..... blah blah more time consuming code ....
next title

end sub
-----
What should I have done differently?

Thanks in advance and have a great day!

Bill Angus, MA
http://www.psychtest.com
 
B

Bill Angus

ok I got the window to repaint by including in the UIdelegate function a line as follows:

me.refresh()

Still not getting the cancel button on the form to be active while the processing is taking place.
 
S

Stoitcho Goutsev \(100\)

Bill,

First of all I don't see anywhere in your application starting a new thread. Maybe that is because I'm not very confortable with the VB syntax or you didn't post this part of the cde.
From what I see the CreateBigCatalog method is supposed to run in a seprarate thread. Is that correct?

If this method runs in a separate thread I'd suggest to move the initialization of the min and max in the UI thread (I'm not sure if this is a problem though). Beside this calling ProgressBar1.Invoke is the correct way of updating the UI from a worker thread.

There some suggestions:

- I'd suggest to post more code e.g. how you start the worker thread because if you catalog creation blocks the UI it most likely runs in the UI thread not in a worker thread.
- Instead of calling me.Refresh, which just invalidates the client area and sends WM_PAINT use Application.DoEvents, which will process all messages pending in the message queue thus, the controls on the form will work. Keep in mind though that if you run you working code in a separate thread you don't need to call neither of them because the UI thread's message pump will work normally and all messages will be processed.
- If you write application for .NET 2.0 consider using the BackgroundWorker class. It is meant to be used for running lenghty operations that need to report their progression. The class also takes care of marshaling the notifications to the UI thread, so you don't have to call Control.Invoke anymore. See the MSDN for this class it comes with a sample.


As far as it goes about articles they are all over the net.

http://msdn.microsoft.com/msdnmag/issues/03/02/Multithreading/

http://msdn.microsoft.com/msdnmag/issues/04/05/BasicInstincts/

just to list a few


--
HTH
Stoitcho Goutsev (100)


ok I got the window to repaint by including in the UIdelegate function a line as follows:

me.refresh()

Still not getting the cancel button on the form to be active while the processing is taking place.
 
B

Bill Angus

Dear Stoitcho: Thanks v. much for all your helpful information.... I feel like I owe you a case of beer at least :)
 
B

Bill Angus

Got it now.... Actually since this doesn't need to be a background process, there is no need of another thread (which I suppose is just a way of sharing processing between competing needs anyway). As long as there is a way for the big loop to call for an update of the UI and to check the message pump to see if the process has been halted -- a single thread works fine. So Application.DoEvents is perfect for me

My processing takes place inside a big nested loop and opens about 5 files simultaneously. I set the cancel_button_click to toggle a boolean variable bCancelled =true. Then within the worker loops I can check and exit the loop gracefully if bCancelled=true (closing files and writing the footers as I go) .

Thanks again, you really helped me a lot on this one.

Bill,

First of all I don't see anywhere in your application starting a new thread. Maybe that is because I'm not very confortable with the VB syntax or you didn't post this part of the cde.
From what I see the CreateBigCatalog method is supposed to run in a seprarate thread. Is that correct?

If this method runs in a separate thread I'd suggest to move the initialization of the min and max in the UI thread (I'm not sure if this is a problem though). Beside this calling ProgressBar1.Invoke is the correct way of updating the UI from a worker thread.

There some suggestions:

- I'd suggest to post more code e.g. how you start the worker thread because if you catalog creation blocks the UI it most likely runs in the UI thread not in a worker thread.
- Instead of calling me.Refresh, which just invalidates the client area and sends WM_PAINT use Application.DoEvents, which will process all messages pending in the message queue thus, the controls on the form will work. Keep in mind though that if you run you working code in a separate thread you don't need to call neither of them because the UI thread's message pump will work normally and all messages will be processed.
- If you write application for .NET 2.0 consider using the BackgroundWorker class. It is meant to be used for running lenghty operations that need to report their progression. The class also takes care of marshaling the notifications to the UI thread, so you don't have to call Control.Invoke anymore. See the MSDN for this class it comes with a sample.


As far as it goes about articles they are all over the net.

http://msdn.microsoft.com/msdnmag/issues/03/02/Multithreading/

http://msdn.microsoft.com/msdnmag/issues/04/05/BasicInstincts/

just to list a few
 
S

Stoitcho Goutsev \(100\)

Bill,

I'm glad to here that you solve your problems.

As for the beer... we can work it out :)
 
J

Jon Skeet [C# MVP]

Bill Angus said:
Got it now.... Actually since this doesn't need to be a background
process, there is no need of another thread (which I suppose is just
a way of sharing processing between competing needs anyway).

Not really - it's a way of doing things in parallel. In this case, it's
a way of keeping the UI message pump responsive while doing work in
parallel.
As long
as there is a way for the big loop to call for an update of the UI
and to check the message pump to see if the process has been halted
-- a single thread works fine. So Application.DoEvents is perfect for
me

Application.DoEvents is generally a bad idea. If any of your calls
block (e.g. you're reading from a network drive and there's a network
glitch which means the read takes a while) your whole UI will hang
while that read happens. Ugly.

Application.DoEvents makes things simpler if you *really* don't care
about your UI freezing up sometimes (and if you can guarantee that you
won't be called again within the events - otherwise re-entrancy becomes
an issue) but proper threading is a more "production quality" solution,
IMO.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top