I wrote a single threaded program (winforms meh) and am expecting it to behave like this:
Mainform starts Progress display form
Progress form is rendered fully
Progress form receieves event operationStarted which adds a picture of spinning circle to the form
Long lasting operation starts
Progress form receives event operationCompleted or operationFailed and sets appropriate image
What happens is messy.
Mainform starts Progress display form
Progress form is not rendered fully!
Program hangs for a while
When long lasting operation is complete UI updates
Why the lag with updating windows form?
This is reduced code if necessary
private bool Run(int commandIndex, string fullCommand)
{
if (operationStarted != null)
operationStarted(commandIndex);
// start long lasting external process
if (exitCode != 0)
{
if (operationFailed != null)
operationFailed(commandIndex, Error);
return false;
}
if (operationCompleted != null)
operationCompleted(commandIndex);
return true;
}
operationStarted, operationFailed & operationCompleted are set correctly to update the appropriate images.
This is vastly simplified but I think it should suffice.
Windows is driven by messages which is handled in a queue system.
When you show a window, one or more messages is put into a queue and has to be processed.
One of these messages is going to be a paint message. In response to this message your program is supposed to paint the window (or something inside it) on the screen.
The way the queue system is processed is that your form is owned by a thread that is continuously doing something like:
while (true)
{
var message = GetNextMessage();
if (message == none) break;
ProcessMessage(message);
}
One of the messages this loop handled was a message instructing your program that the user clicked on a button a form.
In response to this, .NET routes this message as an event to your event handler, typically something like "button1_Click", which then executes.
Until your event handler, this click method, returns, this loop is not processing any messages.
As such, if that button click event is doing something lengthy you're said to be "blocking the UI", which is basically "you're not returning in an orderly fashion back to the message loop".
Related
Why will this click event not display the first toast message?
I created a break point and it hits the line to display "Waiting on User Input..." but never displays. I only get a 5 second wait and then an Approved or Declined toast notification.
private void Button_Credit_Click(object sender, RoutedEventArgs e)
{
myToast.Show("Waiting on User Input...");
System.Threading.Thread.Sleep(5000);
if (pc.BuildTransaction())
myToast.Show("Approved");
else
myToast.Show("Declined");
}
You shouldn't use Thread.Sleep, but instead utilize Task.Delay, so you're not blocking the current thread during your specified delay.
If you block your current thread, which in this situation is much likely your UI thread, how do you expect it to be able to dispatch your toast notification?
I have this code:
private void timer1_Tick(object sender, EventArgs e)
{
MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
}
the timer is enabled, with interval = 100.
This result in an infinite number of message boxes to appear over each other, when I was expecting them to simply BLOCK the next event until the current messagebox is closed.
In more complicated applications this could lead to unpreditable results, and its as if more than 1 thread have access to the same function, but actually it is the same thread.
Why is this happening ?
The message box is a modal dialog which pumps the message queue. And so that allows for the timer tick messages to fire, since they are posted to the GUI thread's message queue.
This is always the case for a modal dialog that is shown in the GUI thread. Since each thread has only one message queue, the modal dialog's message pump will pull of the timer tick messages.
It is happening exactly how it should. The tick event is powered by the message loop (unless you're using a threaded variant) and will be called repeatedly unless you block the message loop in some way (think Thread.Sleep or non message based code execution).
The message box doesn't block, it's just another window and as long as the message pump of the application is functioning so will the window, and so as each tick happens new dialogs can be created and stacked up.
A quick solution to this is something like:
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop();
MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
timer1.Start();
}
This would stop the timer, show a dialog and allow the timer to recover after the dialog is closed. This means you'd only get the one dialog and not a perpetual stack of them.
I am working on a C# winform application which continuously navigates some links in a webbrowser control and process the data of that webpage. I need to provide two buttons on the form for Pause and Resume.
On click of button the whole application should get pause processing and after that on click of Resume button it should start again.
So to pause the application, on click of Pause button I made thread to sleep for infinite time by following code.
private void Pause_Click(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
}
But this piece of code unable the user to click on Resume Button on form to resume the application. Also I am not getting a perfect piece of code to resume the application on click of Resume Button.
Can Anyone get me the correct solution for this issue ?
Thread.Sleep method yields execution of code to process scheduler and doesn't get it back until specified time passes. Therefore you can't make sleeping thread wake itself up. You can't even make a working thread wake another sleeping thread (to my knowledge).
You need to accomplish your goal differently.
Separate data processing code to separate, worker, method
Run worker method in separate thread
Share a state variable between UI and worker thread. This variable should pass signals on whether execution should be paused.
From UI thread, set pause signals in shared variable as needed
In processing loop, write handler code for stopping processing
I'll post some pseudo code below on how you should do this:
private bool _Paused = false;
private void OnPauseClick()
{
_Paused = true;
}
private void OnResumeClick()
{
_Paused = false;
}
private void OnRunClick()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(WorkerMethod));
}
private void WorkerMethod(object state)
{
...
while (needToDoMoreWork)
{
// do some work here
...
// if pause requested, wait to unpause
while (_Paused)
{
// Sleep for a short time and check again if paused
Thread.Sleep(100);
}
}
}
You'll need to fill in the blanks according to your business needs.
If you put your UI thread to indefinite sleep, you're going to kill your UI indefinitely. Don't do that.
Your application has some mechanism to know it's time to do its navigation and processing, probably a timer of some sort. If it's a timer, just stop it when you pause the application, and start it again when you resume. If it's some other mechanism, you need to stop it,too, but it's hard to tell you how without knowing what that mechanism is.
In windows form on click on Next I need to display other form and start some processing. Am coding in .Net C#
The problem is before the form is complete visible, the method gets triggered and the processing starts and the UI looks like it crashed. Processing started even before controls are loaded. and once processing is done all controls are visible.
The actual output must be all controls should be loaded and then processing must start.
I need to call the method to start processing after the form (user control) is visible and is loaded completely.
I tried this and this, but no luck.
Added code:
private void FeatureRemovalControl_Load(object sender, EventArgs e)
{
pictureBox2.Image = Properties.Resources.line;
prgbar.Value = 0;
//code to load images and some other stuff
StratProcess();
}
You're calling StartProcess (which seems to block until it's finished) from your UI thread. Because WinForms repaints occur on that thread, nothing is painted, and it appears that your process has hung. You should look at using a BackgroundWorker, or other way to call StartProcess asynchronously.
Best way, if you ask me, would be to start processing asynchronously, so that you maintain full control of the UI and process at the same time.
http://msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.71).aspx
Try calling that method at the end of the FormLoad event, the control should have finished loading by then. If it hasn't that you may need perform some checks and possibly create a custom event that fires when you're happy that it is ready.
Another solution is to have a button that the user must press to trigger the processing, which they will only be able to click once everything has loaded
EDIT: The reason it look's like it's happening is because you're starting the process in one of the control's load method, which I assume is not the last control to load, so it's starts processing before the other controls are given a chance to load. Make StratProcess method public and call it in the FormLoad method of the parent form instead, like so:
private void ParentForm_Load(object sender, EventArgs e)
{
FeatureRemovalControl.StratProcess(); // Should it be called StartProcess instead?
}
Beware though this is still doing the processing on the UI thread, so the screen may appear to 'hang' whilst this is happening so I advise you move it to a background thread as others have suggested.
If I'm firing the event:
var handler = OnMyEvent;
if (handler != null)
{
handler(some_info);
}
then will the execution thread wait until all suscriber methods return to continue the execution after line:
handler(some_info);
?
Or events are fired "in another thread", meaning that it automatically goes to the next line after handler(some_info)?
Events are fired on the same thread and it will block until they are completed. Of course the event handling code itself can spawn another thread and return immediately but this is completely different matter.
Also note that events like button clicks in a desktop applications like Windows Forms apps are put on a message queue and will fire one at a time. i.e. if you press a button and then press another button the second button event will not fire until the first is completed. Also the form will not repaint and will be "not responding" because painting the form is also an event.
Events are fired in the thread that raised them.