Creating "please wait..." for which is not flicker or not responding

mycelcius

Member
Joined
Oct 12, 2010
Messages
9
Location
Jakarta
Programming Experience
1-3
Dear all

I am now developing an app to manage process in my company.
Since the app will mostly do heavy process such as :
1. Qerying a large database
2. Calculating data displayed on grid
3. Editing value on each cell in a grid
and many more

When the app do these stuff, the screen would go into 'not responding" mode, which is quite suck.
I am thinking to show a small form contain of 1 label (please wait...) and 1 picture (animated provess gif), but when I do this, the "please wait" form also go to not responding mode.
Is there any help I could use, or anyone had a successfull exp on this ???
Thank you

Regards

Agung
 
What you need to do is to perform the actually processing on a secondary thread. If the UI thread is busy doing the work then it can;t respond to the user, hence your forms not responding. Let's say that your form currently does this:
VB.NET:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Me.DoSomeWork()
End Sub

Private Sub DoSomeWork()
    'Do some time-consuming work.
    Threading.Thread.Sleep(10000)
End Sub
That is going to freeze up your form for 10 seconds. Now, try adding another form and add to that your animated GIF or just use a ProgressBar with its Style set to Marquee. Also, add a BackgroundWorker to this new form and then add this code:
VB.NET:
Private Sub Form2_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Me.BackgroundWorker1.RunWorkerAsync()
End Sub

Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
    Me.Close()
End Sub
You'll also want to set the form's ControlBox property to False so that the user has no way of closing the form. Finally, change the first form code to this:
VB.NET:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Using dialogue As New Form2
        AddHandler dialogue.BackgroundWorker1.DoWork, AddressOf DoSomeWork
        dialogue.ShowDialog()
    End Using
End Sub

Private Sub DoSomeWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs)
    'Do some time-consuming work.
    Threading.Thread.Sleep(10000)
End Sub
Now, run the project and click the Button. Your dialogue will be displayed for 10 seconds before closing automatically, remaining responsive the whole time.
 
Thanks for the reply dude.
Yes I understand what you are trying to tell me.
Your code saying that the large burden should be the secondary, and not the primary, but in my case, the 'time consuming' work will access (change value) on a grid, which means there will be a cross-thread exception.
Is there any idea on that ??
Thanks a lot

Regards

Agung
 
You can update the UI during the background operation by calling the ReportProgress method and handling the ProgressChanged event. You can also update the UI after the background operation by handling the RunWorkerCompleted event. Both events are raised on the same thread that called RunWorkerAsync. That's how that code is able to call Close on the form in the RunWorkerCompleted event handler.

If your needs are more complex than those events can reasonably handle, you can use the Invoke method of the form or another control to marshal a method call to the UI thread.
 
a different option is to pass the dataset (assuming you're using one) to the background worker and let it process for the whole thing, and in the "RunWorkerCompleted " you just update the UI.
I've just finished a mult-thread communication UI and I had a couple of issues with speed of the process and posted here, the way I've done there might also be suitable for you http://www.vbdotnetforums.com/windows-forms/43753-backgroundworker-gui-update.html

in basics I have a couple of modules full of variables that are read by both the UI thread and the worker thread... it's not a fancy solution, but due to the large array of different data I had, it was straight forward to implement.
 
Thank you for all guys, I got it working already.
Finally I decide to use the UI thread to process the data inside a grid and use a background worker to show 'waiting form'
while push the app to refresh using aplication.doevents().
I know this will slow down my app during process, but it do simulate a processing effect users want.
Thanks again
 
Thank you for all guys, I got it working already.
Finally I decide to use the UI thread to process the data inside a grid and use a background worker to show 'waiting form'
while push the app to refresh using aplication.doevents().
I know this will slow down my app during process, but it do simulate a processing effect users want.
Thanks again

What you do is up to you, but that's a very poor option. You should just do it the proper way.
 
Hmmm....I see, you got the point there
So this is the detail :

- On an MDI child form, I had a datagrid control used to display database content
- After displaying the data, I would need to change some columns of all rows, so I use loop and starting a value update on each cell (this will be the large process, since rows number can be up to 1000-2000)
- If I use secondary thread to do this job, there will be cross-thread exception since the secondary thread was used to change a datagrid value which was created on a main thread.

So, what are you suggested to do ?
Thanks a lot
 
Assuming the datagrid is bond to a dataset you can simply call the background worker passing the table to it DS.tables("MyTable")
check msdn: BackgroundWorker.RunWorkerAsync Method (Object) (System.ComponentModel))

the BG worker do all the its thing manipulating the datatable, and whenever it's over it shouldn't even need to do anything cause it's all updated already.
 
Back
Top