I'm trying to show a loader animation when my application it's blocked for more than 500ms.
I want that to be automatic, I don't want to add any piece of code before every long operation.
I know that in WinForms it was possible (I used this: https://snipplr.com/view/24851/), but It does not work in WPF.
I've found that I can do that with the mouse cursor(display Hourglass when application is busy)
I've tried to launch a window with a spinner.
I've found this answer (https://stackoverflow.com/a/21411656/10820863), that works detecting long operation.
Problem is that if I launch a window from a thread that is not the main one, I got a ThreadException because it's not the main thread. If I use Application.Current.Dispatcher.BeginInvoke
method, the window appears only when UI is not blocked anymore.
So, how can I automatically detect long operation and show a loading window/page/image/whatever if it lasts for more than 500ms?
[EDIT]
I don't want to add code to every long function, evaluating case for case which function can be long.
I'd prefer to have an automatic method that do that for me.
Related
I am new to Winforms development and I do not see a solution yet on Stackoverflow, but may have missed it.
I have a dialog box that comes up, but due to application startup processing, it is only half displayed for the first 2 seconds or so (i.e. shows border and the background except where controls will be shown). The control locations are white until controls are displayed after that initial 2 seconds.
I understand I could put a delay in the application while it is starting up, but would prefer something like a Suspend() / Resume() pair in strategic locations. I have tried putting in the load event, but that had no effect. Also, it looks like Refresh() breaks the Suspend/Resume. Ideas appreciated since I would like to use this strategy elsewhere in the application as well. I am wondering what is an approach that will work for this and other areas that flicker badly (or outright show a long delay before fully displaying like this startup dialog box as described).
Try putting your long-running code in the Load event handler instead. By putting it in the Shown event handler, it causes the form to freeze until it's done loading because the shown event handler is not letting other events in the message loop, e.g. the Paint event -- get processed. At least if you put it in the Load event, all the long running code will occur before anything gets displayed at all.
If you don't like having any delay, consider putting the long running code in a timer that kicks off in the Shown event.
Then there's always the BackgroundWorker if you want to get more advanced with long-running code.
I'm writing a WinForms window in C# which displays about 12 ListBox and 6 ComboBox controls each with a few hundred to a few thousand items.
It takes a little while to populate these. Not a long while - just a few seconds, but it's nice for the user to have something to look at so they know the program is working away in the background while they wait.
I have a generic "Please Wait" animated borderless top-most window which appears while this happens, however I'm having trouble with the animation.
For most tasks which take a little while, I solve this in the following way:
Program.ShowPleaseWait(); // Show top-most animation
Thread t = new Thread(stuffToDo); // Run stuffToDo() in separate thread
t.Start();
While (t.IsAlive)
Application.DoEvents(); // Run message queue, necessary for animation
Program.HidePleaseWait(); // Hide top-most animation
and it works quite well. Occasionally the stuff in the thread will need to Invoke something and that sometimes causes a small hiccup in the animation, but it's generally not a big deal.
With this form, however, the entire code in the thread is UI code: populating ListBoxes and ComboBoxes. That means everything would have to be enclosed with Invoke blocks, which doesn't make any sense because then there's no point in having it run in a separate thread in the first place.
Aside from scrapping the whole worker thread for this particular case and throwing in an Application.DoEvents() every hundred or so insertions in each loop, is there anything I can do to allow the working animation to continue while the controls are populated?
Just run your animation in a second thread. You're allowed to have multiple UI threads, what's not allowed is accessing any UI object from a thread other than the one that initialized it. The new thread should accept an instance of LoadingAnimationForm (or whatever you call your animated dialog) and call Application.Run(animForm); When the main thread gets done populating everything, call animForm.Invoke(animForm.Close). Do not call any other methods on animForm from the main thread.
One possible approach is to use idle time processing for performing your populating code. So you create a dialog box class that is used to show yours waiting animation. You hook into the idle time processing event at the same time you show the waiting dialog box. Once the idle time processing has fully completed you send a message to your dialog telling it to quit.
The only complication is you need to organize your idle time event so it only performs a little work each time it is called, rather than performing all of it in one go. If you perform it all in one go then the dialog never has chance to process and show an updated wait animation.
Taken from this post:
May I add this CodeProject link?
All you need is to build, drag from toolbar and use. The LoadingCircle component works without any trouble at all. Works like a charm, you can even customize it!
I am having a very difficult time trying to debug/fix an application.
Briefly:
- I created a "wizard" type app that starts with the user taking a photograph (using the common dialog for photos)
If the user tries to use the text input window (SIP) (the little keyboard input window) after a photo is taken the event loop seems to hang - the event is not processed or is delayed for a while.
If the user does not take a picture the SIP keyboard works great.
This only happens on some of my devices. Specifically it is not a problem on an MC65 but is a problem on an ES400.
It appears that the app's event loop gets screwed up with the way I am displaying forms and taking photos.
If created a simple test app with single form containing a button (Event handler takes a photo) and a text box that accepts input. That works fine. But it is only a single form app that does nothing else.
When I combine the photo taking with my form displaying (making a "wizard" ) things go badly.
I wonder what kind of event loop should I be running?
Essentially the user takes a photo then goes through some forms (I hide one form and show another when they click the "next" button.)
The Form.Show is called from the main form after a picture is taken and then I have something like:
while(UserNotFinished)
{
Application.DoEvents()
}
Where UserNotFinished is a flag set from my wizard/forms after the "submit" button is pressed.
I will be happy to provide more code but not sure what would be useful.
I am new to C# and CF development (lots of years of C++/Win32)
The real confusing part is that this works on one device but not on another. In fact, the device hangs completely. It ends the activesync connection and sometimes I have to hard reset by removing the battery.
I think your problem stems from the while(true) { DoEvents(); } and perhaps how you are trying to go between forms. The only time I've used the DoEvents() method is when I'm already in the scope of a windows event and I need to be sure something in the message queue is processed so screen updates are correct. I'd suggest making a controller class to manage the screen flow for your wizard. You can control the screen flow by either using ShowDialog() and execute the flow control directly in the scope of a single call, or you'll have to use Show() and an asynchronous mechanism such as subscribing to and handling specific form and control events in the controller class. Also saw the comment about introducing another thread, beware that Forms belong to the thread they were created in and you must Invoke(...) all Form members in the context of the creating thread.
Hmm. Very strange
I started a new thread and basically call Application.DoEvents() in in as well and it seems to fix the problem...
I don't know why the
while(true)
{
DoEvents()
}
in the main thread doesn't work.
when my program in any process (load csv file for example)
i see 'program Not Responding' and i see black screen - in Windows-7
in Windows-XP i dont see it
(after this the program Continues normal)
Why is this happening ?
When a long process is running, if it's running on the UI thread, that causes the application to not respond to other UI events, most notably drawing the screen. In both Windows XP and Windows 7, this will cause application to be reported as "not responding", but XP and Windows 7 handle window painting differently.
In XP, the application actually updates the screen, but in windows 7, the OS saves what the current screen looks like, then displays that on the screen using a different mechanism (for example, with Aero enabled, it actually displays the contents of the windows using textures in pseudo-3D).
In 7, this can cause applications that are not responding to display black (or the last-known screen in faded grey, depending on graphics settings) screens (because it doesn't have any up to date information). Whereas in XP, it leaves the old content up, but dragging a window over it causes shadows of the window to be displayed on the screen, because the lower window is not updating.
Update:
How do you fix it? Well, there's a bunch of different things, but if you have a method that takes a very long time:
private void SomethingThatTakesAReallyLongTime()
{
System.Threading.Thread.Sleep(30000);
}
Your event handler can look like this:
private void button1_Click(object sender, EventArgs e)
{
((Action)SomethingThatTakesAReallyLongTime).BeginInvoke(null);
}
This may not be a good idea in many cases, but it's a simple example of things you can try.
You are tying up the UI thread (main thread) for an extended period of time likely because the operation is intensive (either CPU or disk). Try moving the intensive operation (say reading file) into a second thread. This will keep the main thread (one w/ UI) responsive to the user and OS.
There are numerous methods to accomplish this. Using a BackgroundWorker is the simplest to implement. This should get you started:
http://msdn.microsoft.com/en-us/library/cc221403(VS.95).aspxr
Esesentially you will:
Create a backgroundWorker
Create an event handler for the DoWork event and wire it to DoWork.
Place the CPU intensive operation inside the DoWork event handler.
Call the RunAsync() method of the backgroundWorker (which will keep off DoWork event)
You can get more complex with providing progress and allowing user to cancel. Here is an example of loading large file:
http://msdn.microsoft.com/en-us/library/ms229675.aspx
This happens when your main thread is working on a relatively long-running task and therefore cannot repaint the screen. Thy using a worker thread to load the csv (for this example) and you shouldn't have this problem.
More than likely, it's happening because you're trying to execute a long running process on the UI thread (which blocks the UI thread so that it can't redraw the form).
You should use some form of Threading to start the long running process on a separate thread so that the UI can continue to function.
I have embedded a console window within my Windows application form using ะก#
I have an application that runs in the console window. my c# project is a GUI to display the output of this and also to send parameters to it.
Most is working fine except when a call to _getch() is made from my GUI to the console window it tends to freeze up the whole system.
anyone got any ideas why this would happen?
I can post code if need be.
Thank you
Odds are that _getch() is a blocking call.
The _getch() function won't return until the user presses a typing key on the keyboard. If this function is called from your program's main thread then this will stall the UI thread. It won't pump the message loop, your UI freezes when it no longer processes input events nor paints the windows. After a couple of seconds Windows puts the ghost window in place with "Not Responding" in the title bar.
While calling _getch() from a background thread will solve the problem, that's probably not going to be convenient. You can use _kbhit() to check if a keystroke is available. Calling _getch() after _kbhit() returns true won't block. Probably not convenient either. Trying to pump the message loop while _kbhit() returns false would technically be a solution, if it wasn't for the message loop living in the wrong code.
Note that you can type Ctrl+S in the console window to pause output, Ctrl+Q resumes it again. You'll still block the UI thread but at least you'll do it knowingly.
What does _getch() do. You can start the call in another thread if its blocking the UI thread.