C# how to efficiently wait x seconds - c#

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.

Related

Is There a way to capture a keydown event in an unresponsive form

I have a form and it has a time consuming method that runs in it. I want to cancel that method with a keypress while it's running, however due to some limitations, i can not convert that method to a task or anything async.
The scenario is, user presses a button, the button calls that method (lets say it runs a while(x > y)) which has takes some, and if the user presses the esc key, i want to break that method.
How can I capture the keypress of an unresponsive form? Since while method blocks the form, keypress methods of the forms are unresponsive.
You can try calling Application.DoEvents from your time consuming method, but that will process also all kinds of messages, including dangerous ones like attempts to close the form, and so on.
Much better if you can rework your code and place our long-running method in a BackgroundWorker.
As you said, it is unresponsive and will be unable to capture input.
Instead you can implement a background thread do your job there thus you can cancel thread as you want

Using the Application.DoEvents()

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()

System.Threading Sleep function help? (C#)

I'm new in C# and I'm using System.Threading.
I have this code:
UISystem.SetScene(Scene_Menu);
Thread.Sleep (9000);
p.Text="HELLO";
Thread.Sleep(9000);
p.Text="WORLD";
It delays 18 seconds, but the p.Text="HELLO" doesn't show between the sleep functions. What's the problem with my code?
Thanks.
Timers don't work since I can't edit p from a separate thread.
Application.DoEvents() is a Windows Forms function, I'm building an application in PS Vita.
You have discovered why you should never use Thread.Sleep. It is useful for only two things. (1) Writing test cases that need to simulate a thread being busy for a certain number of seconds, and (2) Sleeping for zero milliseconds tells the operating system "I cede the rest of my time slice to another process if there exists one that wants it"; it's a politeness thing.
You should never use thread.Sleep to introduce a delay as you are doing for exactly the reason you have discovered. You are setting a property, but setting a property does not cause the operating system to repaint the screen. Consider if it did; you might have a thousand property sets in a method, and you would have to repaint the screen after all of them, which would look ugly and be very slow.
Instead what happens is the property is set and the object makes a note to the operating system that says when this thread is available to handle operating system messages again, please repaint me. Your program is, instead of telling the operating system "I'm done, go ahead and see if there are any message for me" that instead you want the thread to do nothing for nine seconds.
Now, you can tell the program to check for messages by calling DoEvents but using DoEvents is also a bad idea and you should not do it. Doing so essentially causes your program to exhibit symptoms of Attention Deficit Disorder; you have not finished the current job and you are looking to see if there are new jobs to do without removing the old jobs from the call stack! Suppose those new jobs in turn get interrupted, and so on, and so on. The stack grows without bound, which is very bad. DoEvents is a "worst practice", just like sleeping a thread. You can get away with it in small simple programs but it leads to big trouble when the program becomes complex.
Moreover: yes, DoEvents will paint your control, but that is all it will do. For the next nine seconds, the application will appear to the user to be completely hung. That is a very bad user experience.
The right thing to do if you want to introduce a delay is to asynchronously wait. In C# 4 and earlier the standard way to do that is to create a timer, and when the timer ticks, do the next thing.
Now, you say that you cannot use a timer because you need to access the control from the UI thread. That's fine. The timer's tick event handler will run on the UI thread, not on a separate thread. You can safely use a timer.
In C# 5, the right thing to do is to use the new await keyword to introduce an asynchronous wait. That is, a wait that does other stuff while it is waiting, instead of going to sleep while it is waiting. In C# 5 you would write your code as:
UISystem.SetScene(Scene_Menu);
await Task.Delay (9000);
p.Text="HELLO";
await Task.Delay(9000);
p.Text="WORLD";
C# 5 is at present in beta; for details on this new feature see:
http://msdn.microsoft.com/en-us/async
For a gentle introduction to async and an explanation of why DoEvents is bad news, see my MSDN magazine article:
http://msdn.microsoft.com/en-us/magazine/hh456401.aspx

C# Event Handling Order

The scenario is an event on a buffer, that informs interested classes when there is data available to be collected. The event is fired as soon as new data is written to the buffer. When this is fired, the delegate for the event (in the interested class) starts reading data from the buffer.
My question is, if the event were fired again (before the method had finished reading all the data from the buffer) would the reading method be 'reset' or would the event wait for the method to finish reading the data before calling it again?
The event could only be fired again before the method had finished reading if it were fired on another thread. The event handlers will then (by default) be called again in that separate thread. There's no concept of an existing method being "reset", nor would it wait for the already-running handlers to finish before firing again.
Of course, you could potentially change how the handlers work, or how the event is fired - perhaps ensuring that the event handlers are only called from a single thread, with some sort of queue of events. It's impossible for us to tell whether that's appropriate for your situation though.
Neither, it would execute it alongside (in parallel), if on separate threads - otherwise execution would be blocking anyway.
Unless you've put Application.DoEvents() in your code (which is a horrible thing to do) then your event won't be interrupted.
In a multithreading scenario, there's the possibility of them running in parallel. I don't use multiple threads and events both at the same time, so I can't really say much about that, but it seems like Jon's covered that one nicely with his answer.

C# Sleep for 500 milliseconds

Could you please tell me how do I go about pausing my program for 500 milliseconds and then continue?
I read Thread.Sleep(500) is not good as it holds up the GUI thread.
Using a timer it fires a callback ...
I just want to wait 500ms and then continue to the next statement.
Please advise.
EDIT: I need to display a status bar message for 500ms and then update the message with a different one. Sorry, I meant 500 not 50.
EDIT: I do understand what all you have said. but: [I just want to wait 500ms and then continue to the next statement.] I think because it is such a short interval i am going do a Thread.Sleep(500) on the main GUI thread. Otherwise i would have to rewrite a lot of code to accomodate this brief interval of 500 milliseconds.
EDIT: i will try to reformat my status message so the pause is not needed.
Hmya, what you're trying to do is pretty fundamentally incompatible with the Windows programming model. A native Windows program is event driven. Your program is always idle, sitting inside a loop started by Application.Run(), waiting for Windows to tell it that something interesting happened that it should respond to. Paint requests, mouse clicks, timer expirations, stuff like that.
Your program should respond to this and filter what is interesting to you. When you drop a button on a form, you are always interested in the Click event, generated when Windows sends the MouseDown notification message. Your Click event handler runs some kind of custom code that you write. Like updating a status bar message in your case.
Updating the status bar message half a second later doesn't make a whole heckofalot of sense. What exactly happened during those 500 milliseconds that changed the way your program responds to events? You can call the Update() method of the StatusBar so the new message is visible, then call System.Threading.Thread.Sleep(500) to get what you want. You'll get away with it, the "Not Responding" ghost that Windows puts up takes your program going dead for several seconds.
But that doesn't make a lot of sense, nothing happened during that half second, the state of your program didn't change. It couldn't change, it was dead to Windows and not receiving any messages that would allow it to change state.
Well, that's about as far as I can take this. Please update your question and explain why you need to do this. Just in case: if you're contemplating this to fake doing something important for half a second, your user will not be impressed. She'll eventually notice your UI is dead for half a second without anything to show for it.
You have two choices:
Use a timer as you suggested. Split your method up into two methods, foo1 and foo2. Use the foo1 to start the timer and run foo2 in the callback.
Use a BackgroundWorker for running the entire function and use Thread.Sleep on the worker thread.
From your update it seems that the only thing you want to do is change a single field. I would definitely recommend the first method: using a timer. Starting a BackgroundWorker for this task is overkill and will just give you unnecessary extra work and complications.
Instead of pausing the UI directly for 500 ms, you can always use a BackgroundWorker. That will cause your callback to run in a separate thread, where you can use Thread.Sleep to pause it without blocking the UI. Then when you are done, just update the status bar with your new message.
More context to the question would be helpful.
Thread.Sleep(50) will pause the current thread for 50 milliseconds. If you're doing this in the UI thread, then yes, it will freeze the UI for 50 milliseconds. However, if you use a different thread to do this processing, then calling Sleep on that thread will pause it for 50 milliseconds without freezing your UI thread.
See Marc's answer to this question for an example on using a BackgroundWorker instance to do what you need.
In C# your best bet is to use the Timer and fire a callback.
In F# there is an awesome way to do what you want, see
F# async on the client side
which shows how to write straight-line code and have the language take care of the callbacks for you.
You need to allocate another thread. In that thread you Sleep(500) and change the needed data. Caution: you would need to use the original thread's dispatcher, because the data related to UI should be usually updated from the GUI thread.

Categories