Detect Not Responding in Own App
Is it at all possible to detect when your application stops responding, so appropriate action can be taken automatically, instead of the user havin开发者_StackOverflowg to go to task manager/end process and/or end task etc?
Bear with me on this - it's not a direct answer to your question, but rather some design advice to avoid getting into your situation. If your app is truly locked up and not responding the there's really no way to detect it and respond. The trick is to avoid getting into the situation to begin with.
In my experience, WinForms apps almost never just stop responding. Instead, they tend to appear unresponsive while performing long-running tasks or getting caught in infinite (or at least long running) loops.
You can avoid this by putting long running processes in another thread, using multi-threading techniques. An easer trick that works for long running loops is to put the code
Application.DoEvents()
inside the loop. This will allow the app to appear responsive wile the loop is running, when it would normally just appear locked up.
The way I normally handle this is by having a status label that I keep updated to let the user know the app is doing something like shown below:
foreach(DataRow r in myTable.Rows)
{
StatusLabel.Text = "Now processing " + r[0].ToString();
Application.DoEvents();
... now do the real work
}
This gives the user the feedback to let them know the app is actually doing something, and not just "Locked Up". 99% of the time, the user perception is all that matters.
Edit - added to answer the comment below
Application.DoEvents() does include a performance hit. You need to decide on whether it's worth it. Used as I've shown above (in combination with a progress indicator of some sort), it can eliminate user frustration, and I've found it to be a worthwhile trade-off for long running processes.
My original answer mentioned the perception being all that matters 99% of the time. I'll give an example of where I used it and felt it was justified.
I inherited a WinForms application written by one of my predecessors. This application had a process that needed to be done weekly to summarize and process millions of records. On top of the large quantity of records, the database was not designed properly, and as a result the process took over an hour. So the user would be stuck at their computer for an hour watching this screen do nothing. They had no way of knowing if the app was actually working. I added the code above as a temporary measure and the end user was extremely grateful. He really appreciated knowing that the application was really working and not just hung up.
Adding the application.DoEvents() brought the processing time up from an hour to an hour and five minutes or so. It was a noticeable slow-down, BUT the user was happier with it, because even though it took longer, he knew what it was doing.
Incidentally, it made me happier as well because occasionally, when it took longer due to unusually high record counts, the user wold end task on the program and re-run it thinking it was locked up, This would inevitably lead to me having to spend hours fixing the data.
As a final side note, I re-wrote the app from scratch, including redesigning the database, and the same process takes 5 seconds now. I add this not to brag, but to get you to think about why your app seems to be locking up. If you can approach the task in a way that is more efficient and get a better design, you can avoid this completely in a lot of cases.
You should try to make your application do not stop responding, instead.
One way of doing it is to launch those complex tasks in different threads, and after a timeout kill'em.
The most you can do is to keep a count of how long an operation takes, and if it is taking too long, then just kill it. Of course the operation must have a something like CancelEventArgs
in it that your main application can subscribe and invoke.
Another approach is to launch the operation in a separate thread, and in the main thread, keep a count of how long that thread is running and kill it if it's taking too long.
I would do it that way: have a timer firing regularly in the main thread, resetting a counter to 0. Then, in another thread, have another timer that increments the counter. When the counter has reached a certain value, it means the main thread has stopped responding for some time.
精彩评论