Using the Application.DoEvents() - c#

I am facing a problem that Application.DoEvents() can solve. The problem is that WebBrowser suppose to navigate to a url asnychronously but it does't, and when I use Application.DoEvents() it solves that, I think this happens because the application handles some other events and doesn't deliver the events of the navigation properly.
I read a little about this method and I understand that method will cause the application to handle all the currents events. Now I am a bit concern because I used a cannon to kill an ant, Can someone tell me if what I did is worthwhile?

Yes, Application.DoEvents() solves this problem. The core issue is that WebBrowser is a heavily threaded component at its core. You can call its Navigate() method and it goes off doing its stuff without blocking your code, the method returns almost immediately.
The problem however is that at some point it has to run your DocumentCompleted event. Which is guaranteed to run on the thread on which you created the browser object. That's hard to do, your thread may well be busy doing something else. Like sitting in a loop, testing the ReadyState property. There is no mechanism to interrupt this loop and run the event handler.
So what you see is that the ReadyState property never changes and the DocumentCompleted event never fires. This is called deadlock, a very common curse of threaded code. Using DoEvents is the back-door, that "pumps the message loop". It allows the browser to break into your thread and fire the event. Which in turn updates the ReadyState property and lets you break out of the loop.
There's a Big Problem with DoEvents however. it isn't selective, it doesn't just limit itself to handling the message that allows the event to fire. It also dispatches other notifications, the kind that will crash your program. Like your user getting impatient with the slow web site and closing your form. That destroys the browser object but does not stop your loop. You are now testing the ReadyState property of a disposed browser. Kaboom!
You'll need to do this differently. It is never legal to block or hang up the UI thread in a loop, it is very prone to create deadlock. It is in fact forbidden by Microsoft guidelines for an STA thread. The workaround is simple, move whatever code you now have after the wait loop to the DocumentCompleted event handler. You might need to add some state variables to your class so that you know that the event signals completion of a particular web page or that the user is no longer interested in the result.

The Application.Dovents() method makes all pending messages processed. That can cause:
Entering a code block twice before the current one finishes. (Let's assume that you navigate your browser with a button click. User clicks the button and while your code is waiting browser to copmlete the user clicked again. In that case Application.Doevents() will cause processing that method before stepping next line.)
Interrupting critical codes. (Lets assume that you have a time consuming method and the user clicked close button. Your form will disappear but your code will continue to run. A real problem.
Many more UnExpected results.
However I feel sometimes using this method is necessary and an easy solution like webbrowser which is difficult to use in multithreading (especially when its visible). If you have to use this method you should be sure that user and other things (timers, buttons, events vs) don't interrupt anything.
For a detailed discuss:Use of Application.DoEvents()

Related

C# how to efficiently wait x seconds

My algorithm automatically fills metadata in a specific website (using webBrowser). After fill metadata the algorithm press the button send (in website) and it must wait a few seconds for metadata to be analyzed before contiune (this is not part of algorithm, but webpage). The problem is that i have no way to know when metadata analsys finish. I try the next code, which is used to wait for fully loaded webpage before continuing with the processes:
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
But it's useless becuse metadata analysis is not related to webpage loading.
So, because metadata analysis takes about 20-40 seconds i think that wait about 60 seconds and continue is a good solution. I try:
System.Threading.Thread.Sleep(60000);
After programmatically press button "send", but for anyreason this wait for 60 seconds before button is pressed.
I don't think I completely understand why you're wanting to do what you're asking for here, so I'm attempting to answer this question with what information I have here.
If you're calling Thread.Sleep in an event handler (say, an event handler for a Button's click event), Thread.Sleep will effectively pause the program, since you're still on the UI thread. I'm guess this isn't what you're after?
If you want the UI thread to continue (where you're probably doing the bulk of your work), you'll need to make the Button's click handler async, and use await Task.Delay instead. You can see the pattern in use here: Should I avoid 'async void' event handlers?
Additionally, you can probably figure out a way to call back into your application using techniques detailed here: http://www.codeproject.com/Articles/35373/VB-NET-C-and-JavaScript-communication
Using that method, I'm sure you can get rid of the waiting altogether.

How can I run UI on a thread other than the Main UI thread in .net?

I know there are other questions around this but most end up with the answer don't do what I am about to suggest. So I know you aren't supposed to. The reason for this question is I want to do it anyway, how can I do it...
Here is why I want to break the rules...
Let's say I have a complicated application, it's version 1 and we want our customers to submit errors to us in the event of crashes or hangs. Let's now say I have a button on the top of the main form they click to submit reports.
Let's now imagine that the application hung because of a deadlock...
It would be nice if that small piece of UI and a handler for that button could live on a thread other than the main ui thread so that it isn't caught up in the deadlock. When clicked it would gather all the call stacks for the other threads and submit them to our error reporting service.
Now, knowing the scenario, can this be done in .net?
Yes, there is no magic in creating UI on another thread than the "main thread". The important rule to always keep in mind is to interact with that UI on the thread that created it.
Still, I feel that you are attacking this from the wrong angle. You should probably instead make an effort to push all work off the main thread. That way you minimize the risk for that thread to freeze, and then you don't need to resort to unorthodox solutions for the error reporting.
I have various cases of creating forms on non-main thread, and it works fine every time.
Create a new Thread, and show a Form from it. New message loop will be created for that thread and everything will run fine.
What magic will you use to gather data from the crashed app and locked main thread, that's up to you :)
if application hung, your main message loop is dead, thus ui will not work. As workaround for your problem i'd consider usage of external application (another exe) which will be invoked in case of report
in any case, if you want to invoke UI from other thread you should perform context switch In case of winforms, follow this answer
It sounds like you'd like to keep the UI alive, even when some other operation is mired in a deadlock. If so, perhaps Asynchronous Programming would be of use. Using Async to manage a potentially hung up task would allow the remainder of the application to remain responsive.
we want our customers to submit errors to us in the event of crashes or hangs
You might also consider adding some degree if instrumentation/reporting, so that you'll have this data without requiring user input.

Why is it an abuse to call refresh()?

Like in this example:
someImage.Source = newSource;
someImage.refresh();
A few days ago in this post I responded with refresh() and I got feedback that it's a hack/abuse. I don't understand why.
The MSDN has the answer.
Control.Refresh:
Forces the control to invalidate its client area and immediately redraw itself and any child controls.
Control.Invalidate:
Invalidates the entire surface of the control and causes the control to be redrawn. […] Calling the Invalidate method does not force a synchronous paint
[Emphasis mine]
The point is that Refresh, unlike Invalidate, forces a synchronous call, which effectively interrupts the default event flow in forms and cuts the line in the message queue. This may cause other window messages (events from the operating system) to be delayed.
The Refresh method call is not needed at all if you have a responsive user interface. Setting the Source property creates a message that invalidates the display of the control, so it will be refreshed automatically when that message is handled.
It's only if your code contains a long running loop, so that it doesn't handle messages at all for a long period, that you need to use the Refresh method. Such a long running loop should be avoided, as it causes the user interface to be unresponsive.
by simple words Refresh() will reloads the UI, when some change
Because most gui frameworks handle refreshes/updates automatically if you use them correctly.
With refresh you work around the symptom (something is not automatically updated) instead of solving the root cause.
The problem is that Refresh usually start to spread like a virus. You insert it in one place and suddenly you need it in a second place, and third etc.

Use of Application.DoEvents()

Can Application.DoEvents() be used in C#?
Is this function a way to allow the GUI to catch up with the rest of the app, in much the same way that VB6's DoEvents does?
Hmya, the enduring mystique of DoEvents(). There's been an enormous amount of backlash against it, but nobody ever really explains why it is "bad". The same kind of wisdom as "don't mutate a struct". Erm, why does the runtime and the language supports mutating a struct if that's so bad? Same reason: you shoot yourself in the foot if you don't do it right. Easily. And doing it right requires knowing exactly what it does, which in the case of DoEvents() is definitely not easy to grok.
Right off the bat: almost any Windows Forms program actually contains a call to DoEvents(). It is cleverly disguised, however with a different name: ShowDialog(). It is DoEvents() that allows a dialog to be modal without it freezing the rest of the windows in the application.
Most programmers want to use DoEvents to stop their user interface from freezing when they write their own modal loop. It certainly does that; it dispatches Windows messages and gets any paint requests delivered. The problem however is that it isn't selective. It not only dispatches paint messages, it delivers everything else as well.
And there's a set of notifications that cause trouble. They come from about 3 feet in front of the monitor. The user could for example close the main window while the loop that calls DoEvents() is running. That works, user interface is gone. But your code didn't stop, it is still executing the loop. That's bad. Very, very bad.
There's more: The user could click the same menu item or button that causes the same loop to get started. Now you have two nested loops executing DoEvents(), the previous loop is suspended and the new loop is starting from scratch. That could work, but boy the odds are slim. Especially when the nested loop ends and the suspended one resumes, trying to finish a job that was already completed. If that doesn't bomb with an exception then surely the data is scrambled all to hell.
Back to ShowDialog(). It executes DoEvents(), but do note that it does something else. It disables all the windows in the application, other than the dialog. Now that 3-feet problem is solved, the user cannot do anything to mess up the logic. Both the close-the-window and start-the-job-again failure modes are solved. Or to put it another way, there is no way for the user to make your program run code in a different order. It will execute predictably, just like it did when you tested your code. It makes dialogs extremely annoying; who doesn't hate having a dialog active and not being able to copy and paste something from another window? But that's the price.
Which is what it takes to use DoEvents safely in your code. Setting the Enabled property of all your forms to false is a quick and efficient way to avoid problems. Of course, no programmer ever actually likes doing this. And doesn't. Which is why you shouldn't use DoEvents(). You should use threads. Even though they hand you a complete arsenal of ways to shoot your foot in colorful and inscrutable ways. But with the advantage that you only shoot your own foot; it won't (typically) let the user shoot hers.
The next versions of C# and VB.NET will provide a different gun with the new await and async keywords. Inspired in small part by the trouble caused by DoEvents and threads but in large part by WinRT's API design that requires you to keep your UI updated while an asynchronous operation is taking place. Like reading from a file.
It can be, but it's a hack.
See Is DoEvents Evil?.
Direct from the MSDN page that thedev referenced:
Calling this method causes the current
thread to be suspended while all
waiting window messages are processed.
If a message causes an event to be
triggered, then other areas of your
application code may execute. This can
cause your application to exhibit
unexpected behaviors that are
difficult to debug. If you perform
operations or computations that take a
long time, it is often preferable to
perform those operations on a new
thread. For more information about
asynchronous programming, see
Asynchronous Programming Overview.
So Microsoft cautions against its use.
Also, I consider it a hack because its behavior is unpredictable and side effect prone (this comes from experience trying to use DoEvents instead of spinning up a new thread or using background worker).
There is no machismo here - if it worked as a robust solution I would be all over it. However, trying to use DoEvents in .NET has caused me nothing but pain.
Yes, there is a static DoEvents method in the Application class in the System.Windows.Forms namespace. System.Windows.Forms.Application.DoEvents() can be used to process the messages waiting in the queue on the UI thread when performing a long-running task in the UI thread. This has the benefit of making the UI seem more responsive and not "locked up" while a long task is running. However, this is almost always NOT the best way to do things.
According to Microsoft calling DoEvents "...causes the current thread to be suspended while all waiting window messages are processed." If an event is triggered there is a potential for unexpected and intermittent bugs that are difficult to track down. If you have an extensive task it is far better to do it in a separate thread. Running long tasks in a separate thread allows them to be processed without interfering with the UI continuing to run smoothly. Look here for more details.
Here is an example of how to use DoEvents; note that Microsoft also provides a caution against using it.
From my experience I would advise great caution with using DoEvents in .NET. I experienced some very strange results when using DoEvents in a TabControl containing DataGridViews. On the other hand, if all you're dealing with is a small form with a progress bar then it might be OK.
The bottom line is: if you are going to use DoEvents, then you need to test it thoroughly before deploying your application.
Yes.
However, if you need to use Application.DoEvents, this is mostly an indication of a bad application design. Perhaps you'd like to do some work in a separate thread instead?
I saw jheriko's comment above and was initially agreeing that I couldn't find a way to avoid using DoEvents if you end up spinning your main UI thread waiting for a long running asynchronous piece of code on another thread to complete. But from Matthias's answer a simple Refresh of a small panel on my UI can replace the DoEvents (and avoid a nasty side effect).
More detail on my case ...
I was doing the following (as suggested here) to ensure that a progress bar type splash screen (How to display a "loading" overlay...) updated during a long running SQL command:
IAsyncResult asyncResult = sqlCmd.BeginExecuteNonQuery();
while (!asyncResult.IsCompleted) //UI thread needs to Wait for Async SQL command to return
{
System.Threading.Thread.Sleep(10);
Application.DoEvents(); //to make the UI responsive
}
The bad: For me calling DoEvents meant that mouse clicks were sometimes firing on forms behind my splash screen, even if I made it TopMost.
The good/answer: Replace the DoEvents line with a simple Refresh call to a small panel in the centre of my splash screen, FormSplash.Panel1.Refresh(). The UI updates nicely and the DoEvents weirdness others have warned of was gone.
I've seen many commercial applications, using the "DoEvents-Hack". Especially when rendering comes into play, I often see this:
while(running)
{
Render();
Application.DoEvents();
}
They all know about the evil of that method. However, they use the hack, because they don't know any other solution. Here are some approaches taken from a blog post by Tom Miller:
Set your form to have all drawing occur in WmPaint, and do your rendering there. Before the end of the OnPaint method, make sure you do a this.Invalidate(); This will cause the OnPaint method to be fired again immediately.
P/Invoke into the Win32 API and call PeekMessage/TranslateMessage/DispatchMessage. (Doevents actually does something similar, but you can do this without the extra allocations).
Write your own forms class that is a small wrapper around CreateWindowEx, and give yourself complete control over the message loop.
-Decide that the DoEvents method works fine for you and stick with it.
Check out the MSDN Documentation for the Application.DoEvents method.
The DoEvents does allow the user to click around or type and trigger other events, and background threads are a better approach.
However, there are still cases where you may run into issues that require flushing event messages. I ran into a problem where the RichTextBox control was ignoring the ScrollToCaret() method when the control had messages in queue to process.
The following code blocks all user input while executing DoEvents:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Integrative.Desktop.Common
{
static class NativeMethods
{
#region Block input
[DllImport("user32.dll", EntryPoint = "BlockInput")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool BlockInput([MarshalAs(UnmanagedType.Bool)] bool fBlockIt);
public static void HoldUser()
{
BlockInput(true);
}
public static void ReleaseUser()
{
BlockInput(false);
}
public static void DoEventsBlockingInput()
{
HoldUser();
Application.DoEvents();
ReleaseUser();
}
#endregion
}
}
Application.DoEvents can create problems, if something other than graphics processing is put in the message queue.
It can be useful for updating progress bars and notifying the user of progress in something like MainForm construction and loading, if that takes a while.
In a recent application I've made, I used DoEvents to update some labels on a Loading Screen every time a block of code is executed in the constructor of my MainForm. The UI thread was, in this case, occupied with sending an email on a SMTP server that didn't support SendAsync() calls. I could probably have created a different thread with Begin() and End() methods and called a Send() from their, but that method is error-prone and I would prefer the Main Form of my application not throwing exceptions during construction.

Does WebBrowser's DocumentCompleted occurs on the same thread as the one that calls Navigate?

I'm almost sure it does but I just need to make sure. I don't want my app to be executing another method at the same time DocumentCompleted is being called.
No, it is raised on the thread that created the WebBrowser, the one that's also pumping the message loop that keeps events on WebBrowser alive. Calling Navigate() from a worker thread is technically possible but unwise if you want to keep your ducks in a row.
Yes it does (at least, according to the following picture from VS2010 debugger);

Categories