Is Application.DoEvents really that bad?

I was looking for a way for some text to appear before and after some data processing was taking place. I was using Application.DoEvents so the text would change at each step but I read this is a bad technique. Why is this so bad and what would be the proper technique?

        private void btnScrub_Arrest_Click(object sender, EventArgs e)
        {

            lblProcessing.Text = "Processing starting ... please wait.";
         
            Application.DoEvents();


            Scrub_Arrest_File();    /* Read input csv file, insert records into SQL table */

            Output_CSV_File();      /* Extract full dataset out of SQL and write required fields to output csv files */

            lblProcessing.Text = "Processing complete ... please click Exit.";

            Application.DoEvents();
        }
rwheeler23Asked:
Who is Participating?
 
Chris StanyonConnect With a Mentor Commented:
The modern approach is to use the async / await keywords instead of a Background Worker. If you want to set both tasks running at the same time, then you would do:

private async void btnScrub_Arrest_Click(object sender, EventArgs e)
{
    lblProcessing.Text = "Processing starting ... please wait.";

    var task1 = Task.Run(() => Scrub_Arrest_File());
    var task2 = Task.Run(() => Output_CSV_File());

    await Task.WhenAll(task1, task2);

    lblProcessing.Text = "Processing complete ... please click Exit.";
}

Open in new window

If you need to run the tasks in order (i.e. don't start the second one until the first one has finished, then await the individual tasks:

private async void button1_Click(object sender, EventArgs e)
{
    lblProcessing.Text = "Processing starting ... please wait.";

    await Task.Run(() => Scrub_Arrest_File());

    lblProcessing.Text = "Exporting CSV";

    await Task.Run(() => Output_CSV_File());

    lblProcessing.Text = "Processing complete ... please click Exit.";
}

Open in new window

0
 
AndyAinscowFreelance programmer / ConsultantCommented:
The 'better' way is to use a thread for the computationally intensive work.
The reason why the DoEvents is 'bad' is because the work is being done in the main thread.

Personally I do not consider DoEvents as bad in itself, it really depends on just what is being done.  It is a simple way to make the UI responsive.
0
 
Ryan ChongConnect With a Mentor Commented:
use DoEvents so to let your interface has chance to be refreshed. it depends on the scenario and where we apply it to make a judgement whether it's bad to use it.

the 2nd Application.DoEvents(); is not necessary if there is no further processes after that.
0
Cloud Class® Course: Amazon Web Services - Basic

Are you thinking about creating an Amazon Web Services account for your business? Not sure where to start? In this course you’ll get an overview of the history of AWS and take a tour of their user interface.

 
rwheeler23Author Commented:
The second Application.DoEvents() had to be moved to the end of the Output_CSV_File() method otherwise the message about being completed never appeared. I am sorry but my mind is still stuck in the top - down programming world. My thought was

1 - First message appears
2 - Read input file
3 - Write output file
4 - Second message appears

Well this is not right. I will need to research what you mean by thread.
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
This is one simple to use thread option - the BackgroundWorker:
https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx

There is example code in the link
0
 
rwheeler23Author Commented:
I can think of these threads as another dimension. An application can be doing different things at once each one in its own thread. Thanks for the example.
0
 
käµfm³d 👽Commented:
@Chris Stanyon

Albeit we're kind of guessing as to what goes on in those two methods, it looks like to me there is I/O going on in those methods. If that be the case, then those methods should be async all the way down, rather than invoked via a Task.Run.
1
 
Chris StanyonCommented:
@käµfm³d - Agreed - they absolutely should be!

I'm kind of guessing they're not ;)
0
 
rwheeler23Author Commented:
OK, this could be interesting. At the end of the scrub routine there is a messagebox that pops up to tell them the scrubbing is complete. Until they click OK, the output routine does not start. Likewise at the end of the output routine there is a messsagbox that pops up telling them the output is complete. Looking at your example I can eliminate those message boxes but still have the progress bar moving. This way no clicking of the OK boxes is needed.
0
 
Éric MoreauSenior .Net ConsultantCommented:
MessageBox is a blocking operation. Nothing else will happen in that method until the messagebox has been discarded
1
 
käµfm³d 👽Commented:
Nothing else will happen in that method until the messagebox has been discarded
On the UI thread, anyway.
0
 
Chris StanyonCommented:
This will be down to a UI decision. Do you really need a MsgBox saying "Scrub Routine Finished". If you only give your user an OK option, it's probably redundant. Update the UI (label / progress / icon / image etc) and just move on to the Output. Once that's finished, again update the UI. Popping a MsgBox just to say "I'm done. Click OK" feels a little unnecessary, but that's a call you'll need to make.

Once finished, your message says Click Exit to Continue, so it would make sense to disable the exit button, run the routine, updating the UI along the way, and then re-enable the Exit button once it's complete. Your UI will remain responsive, your User will remain informed, and the Exit button can't be clicked until you decide it can be :)
0
 
rwheeler23Author Commented:
This was a new routine and I wanted the users to better understand what was happening under the hood. Once they get the idea I will remove the message boxes. You thoughts are spot on!
0
 
käµfm³d 👽Commented:
I wanted the users to better understand what was happening under the hood.
Isn't that what your status label is provding?
0
 
rwheeler23Author Commented:
Yes, but the darn users are always pestering me as to why my code can't be completed in 30 seconds or less. I thought by doing this they could see it takes a while to parse 1,000,000 records, then do some manipulations and finally export out a selected data set to a csv file.
0
 
Chris StanyonConnect With a Mentor Commented:
Designing a really nice UI can often be considered a bit of a dark art. If your users click a button and don't see anything happen for a few seconds, they'll be upset and start clicking anything and everything like crazy, but if you give them some feedback, they're much more likely wait patiently.

If your process takes a while, then make use of a Progress Bar, Labels, Spinner Icons - anything that lets your users know that 'something' is happening.

Generally, it's pretty easy to implement feedback using the IProgress<> interface. It only has one method - Report(). Create a Progress instance, pass it into your long-running method, and call progress.Report(xx). It will marshall the update back to the UI so you can update your controls (progress bar / label etc).
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
...can't be completed in 30 seconds...

Anything taking more than a second or two to complete really ought to be run in another thread.
Using a progress bar is a nice way to indicate to a user that something is happening.  If it is easy to determine the progress (eg. in a for loop) then you can display the % completed.  For difficult to display the progress (eg. waiting for an SQL query to complete) then using the marquee modus of the progress bar at least shows something is happening.

ps.  Personally I always got annoyed with Microsoft - time to complete 1 minute, 20 seconds, 5 seconds (then 10 minutes later) 2 seconds (another 10 minute wait) 1 second.  Idea 10/10, implementation 0/10
0
 
rwheeler23Author Commented:
That is the next thing  I need to add. I already have the progress bar and now I want to add the percentage. The first files they sent my way had a few hundred records and finished in no time. Now that this code is in production these files have in excess of 1,000,000 records so it can take a few minutes.
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
This is now well away from the original question.
EE wants to have a database of questions and answers.
I'd suggest you close this question off and ask a new one if you need assistance about a progress bar.
0
 
rwheeler23Author Commented:
I was simply making a statement. I will close this now.
0
 
rwheeler23Author Commented:
Thanks for the tips.
0
 
rwheeler23Author Commented:
Thanks for the tips.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.