Questions and Answers on any aspect of .NET. Now closed.
What's the secret to getting Dot Net/C# to refresh the screen while performing a computation-intensive task, or waiting for a database call? I have some longish proceedures (e.g. 5 minutes) and if the user checks their email (or whatever) and covers the window (which may have cues to the progress of the proc), it is not redrawn until the end.
Use a background worker thread to do the computationally expensive task. In .NET 2.0 there is a new BackgroundWorker object that makes this really easy. If you are using .NET 1.1 you can Google for BackgroundWorker and you will find some 1.1 implementations. Or you can roll your own. This is by far the best way to handle this type of situation.
Tuesday, July 11, 2006
And be sure to ignore any advice that tells you to use DoEvents. It is dangerous if not handled correctly. If someone presses the close button and then you call DoEvents, the result is a real mess if you don't handle every little possbile scenario.
Tuesday, July 11, 2006
Sounds like a good reason to proceed with the upgrade to 2.0. Thanks for the help.
Am I the only one who thinks the Microsoft should have worked this out in the foundation? I don't have a long history working in the Windows GUI, but over 5 years and three or four development environments, this is the only one that I have found that doesn't redraw when the frame is reselected as active.
I will elaborate one particular case to be clear, so you know exactly what my complaint is. I have a process with a loop. Within the loop is the usual mix of calls to the DBMS, computations, and a line gets written to a file. At the end of the loop, there is a ProgressBar.PerformStep() to keep the user informed.
If the user starts the process and leaves the computer untouched, the ProgressBar marches across the window. But if the user covers the window and then uncovers it, the ProgressBar remains frozen until the process concludes.
(This is not a ProgressBar issue. The behavior is the same with other updates to the info on the screen.)
So I am not complaining about the window being nonresponsive during a lengthy call to the DBMS or during long calculations that don't affect visible objects. I understand those situations. But I don't understand why the program fails to update the window as it should after being reselected. I don't recall that behavior fom Powerbuilder or Java.
One thing you can always do is call the Refresh method on the progressbar control. This causes the update to the progress bar to occur immediately. I use this with text boxes and such when I want to show status during a loop. But keep in mind that this technique should only be used with simple controls and short loops. The real solution to long running loops is to use the BackgroundWorker component.
As for any other language causing the update to occur immediately, they are just automatically calling the platform equivalent of the Refresh method after you change the control property. This ability is built into Win32. The default is not to update controls immediately since this causes additional overhead. And from what I remember, PowerBuilder worked the same way as .NET does. It had an equivalent method that you could call (but it's been a while since I worked with it so I could be wrong).
Wednesday, July 12, 2006
It has to do with the nature of windows and how it updates. Under the hood, there's a message loop. When the window is "damaged" (other window moved on and then off it), the OS posts a message to that window's message queue.
Inside every windows application is a loop that looks for messages on that queue. It processes each message, then goes back and idles waiting for a new one.
Here's the problem - while you're off doing the 5-minute db call, your application is NOT CHECKING THE MESSAGE QUEUE. As a result, it's not handling the underlying WM_PAINT message, and your screen doesn't get redrawn.
Updating the progress bar isn't showing this problem becuase the update call causes the bar to redraw right then and there.
The solution here is, as others have mentioned, to do long running work on a separate thread.
> Within the loop is the usual mix of calls to the DBMS, computations, and a line gets written to a file. At the end of the loop, there is a ProgressBar.PerformStep() to keep the user informed.
If you were doing this in C++ you would also want a GetMessage/DispatchMessage loop near where you call PerformStep(): this would be to ensure that any Window messages queued for the application's windows are dispatched.
What's the .NET equivalent of GetMessage/DispatchMessage?
No simple equivalent because WinForms completely hides the message loop. You can get at the raw message loop by overriding some method or attaching some event or something (sorry, please check MSDN Library)... but seriously, you shouldn't be doing this. Just use a background thread, it's the right thing to do.
Thursday, July 13, 2006
NO NO NO NO NO! DO NOT CALL DoEvents! EVER!
Are you crazy? This opens a whole can of reentrance worms. I wished this method wasn't even available. It should be hidden by default, just like the WinMain procedure. :(
Friday, July 14, 2006
This topic is archived. No further replies will be accepted.Other recent topics
Powered by FogBugz