I am going through this tutorial on how to perform some work in the background and in this piece of code I am confused as to why the message reading the file... is not displayed before the ReadTheFile(filename) method is called.
private void btnSelect_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.CheckFileExists = true;
ofd.CheckPathExists = true;
if (ofd.ShowDialog() == DialogResult.OK)
{
lblResults.Text = " ... reading the file ...";
FileReader1 fr = new FileReader1();
int numLines = fr.ReadTheFile(ofd.FileName);
lblResults.Text = string.Format("We read {0} lines", numLines.ToString());
}
}
The author explains it by saying the following, but it did not really get through to me.
Worse, even though we set the label’s Text property before we call ReadTheFile, the message loop doesn’t get a chance to process that change, and update the text, before we go out to lunch in ReadTheFile.
What does this mean? Can this be explained in simpler terms?
Worse, even though we set the label’s Text property before we call ReadTheFile, the message loop doesn’t get a chance to process that change, and update the text, before we go out to lunch in ReadTheFile.
Basically you are setting the text of label. However, you then start doing a "intensive" task that could take seconds, minutes, hours. As long as you are continuing to load the file and read the number of lines, the window will not update. That's the point of doing it in a background thread. Let the main thread continue to paint the window and handle UI stuff while your background thread processes the file.
I would continue with the tutorial. Once you get to the part where you start creating and running the background worker you may end up with one of those "Aha!" moments. =)
You may also be interested in reading up on threads in general.
http://www.codeproject.com/Articles/26148/Beginners-Guide-to-Threading-in-NET-Part-1-of-n
http://www.techrepublic.com/article/a-beginners-guide-to-threading-in-c/1044970
You could read Application.DoEvents Method .
When you run a Windows Form, it creates the new form, which then waits
for events to handle. Each time the form handles an event, it
processes all the code associated with that event. All other events
wait in the queue. While your code handles the event, your application
does not respond. For example, the window does not repaint if another
window is dragged on top.
So, until your btnSelect_Click is finished, your form will not repaint.
I'd edit my answer to remark, that one'd better not use DoEvents explicitly, as it may result in rather weird programm behaviour. (based on comment by J.Skeet).
You could read Use of Application.DoEvents() at SO also for more info. There is an extract from MSDN posted in that thread:
Calling this method causes the current thread to be suspended while
all waiting window messages are processed. If a message causes an
event to be triggered, then other areas of your application code may
execute. This can cause your application to exhibit unexpected
behaviors that are difficult to debug. If you perform operations or
computations that take a long time, it is often preferable to perform
those operations on a new thread.
Related
I tried to use this code and when I pressed my button they all appeared at the same time after what I think is all the thread.sleep time combined
private void guna2Button2_Click(object sender, EventArgs e)
{
Thread.Sleep(1000);
label18.Text = "Step1";
Thread.Sleep(4000);
label28.Text = "Step2";
Thread.Sleep(1500);
label27.Text = "Step3";
Thread.Sleep(6590);
label26.Text = "Step4";
}
I think you want to update the label after the mentioned time.
Try this:
private async void guna2Button2_Click(object sender, EventArgs e)
{
await Task.Delay(1000);
label18.Text = "Step1";
await Task.Delay(4000);
label28.Text = "Step2";
await Task.Delay(1500);
label27.Text = "Step3";
await Task.Delay(6590);
label26.Text = "Step4";
}
they all appeared at the same time
When a windows forms program is running, there is by default a single thread executing all the code. That thread has a really important job; processing all the events from the user and drawing the UI. It only does those things when it is not processing your code that you write in a button click handler etc. If it's doing your code it's not doing those things. When the user clicks a button it stops doing those things and starts doing your things.
It's really important for a good user experience that you don't occupy its attention for very long - let's say you should try and keep to less than a hundred milliseconds. If your code captures its attention for too long the user will notice the UI jams/freezes and if the operating system notices it will fade the window and mark it as "not responding"
Your code as it is captures the thread for a very long time, and prevents it from going back to its normal work of drawing the UI. Thread.Sleep makes it sit doing nothing for the duration of the timeout, and it really does just sit and wait for the time to finish. Then you make a label visible, but the thread won't draw that as visible until you release it from your code and let it go back to doing its work, then you sleep it again. This basically means after 15 or so seconds your code will finally reach the end of the button click handler and the thread will go away, back to drawing your UI with a to-do list of "draw these 5 labels which were make visible whilst you were busy" so they all appear at once
It's an interesting learning point, embodied in the answer Amit posted, and the way try to do things now; when you use async, and await Task.Delay(...) this is very different to Thread.Sleep. Whenever a thread encounters await X it kicks off X as a background operation and crucially, it goes back to what it was doing before it started doing your code which in this case is drawing the UI. When the background operation is done it will be called back to pick up from where it left off.
This means those labels appear gradually, because the thread that is processing your code is spending most of its time actually not doing your code but drawing the UI so it can draw labels as visible very soon after you made them visible rather than being kept busy by your code all the way to the point where your code ends
The lesion you're learning here is fairly important for a lot of your future code. Using async/await is a good way of making better use of resources; threads are resource-expensive things to have sitting around doing nothing. By making better use of fewer threads (by making them fill their time with as many jobs as possible when they would otherwise be sitting around doing nothing) our programs scale up better. This means when you're kicking off an operation to download a 1gb file that will take 30 seconds, you should definitely do it with an asynchronous download approach, otherwise you'll jam your UI/hang your web server thread etc. in the case of a user app, it's just a bit annoying to have the Ui freeze all the time but in the case of a busy webserver, it having to start new threads to service new requests just because all its existing threads are jammed doing nothing means that it can run out of resources pretty quickly
In a WPF application, I am outputting messages to a text box and in between these messages I am calling a function that sets up an instrument. However the messages all appear at the same time (at end of function call).
I do not really know how to explain my problem clearly. I'll try...
I have a WPF application which takes data from an instrument using the serial port. The application contains some buttons and a text box for output messages. Upon pressing a button, the application sends a command to the instrument to change some parameters (through a function Set_COMM_MODE()), and returns. The change takes around 5-10 seconds. Thus what I did is: I outputted a "Please Wait" message before the call and a "Done" message after the call return.
The OuputText() function in the code only calls the TextBox.AppendText() method.
My Problem: All the output text is splurted out on the text box upon the call return. I expected a Please Wait... then 5-10s later a "Done" message. But it is all appearing at the same time. However, when I put a MessageBox after the 1st message (before the function call), the message appears on the textbox output (w/o the function being called). However the problem is that I have to press OK on the MessageBox in order to continue.
Q(1): How can I have the latter happening w/o having to resort to a MessageBox
Q(2): What does a MessageBox do in order to create this behaviour?
I tried: using the Dispatch.Invoke() method to run the OutputText on another thread.
This (Pause a window like MessageBox.Show()) is a similar problem to what I have, but didn't seem to get a definitive answer, and I did not understand the solution well.
void StartTest_btn_Click(object sender, RoutedEventArgs e)
{
OutputText("Please Wwait\r\n"); //<---- This should appear at once.
MessageBox.Show("Please Wwait"); //<--without this, both messages appear at same time after 10s.
Set_COMM_MODE("02"); //<--- This takes around 5-10s
OutputText("Done\r\n"); //<--- This should appear 5-10s later
}
I expect a "Please wait" to show at once, then 5-10s later the "Done" message to show, after return of function Set_COMM_MODE().
As I wrote in my comment, you should really use the (main) UI thread for UI only.
Perform any other long-running non-UI operations on worker threads.
You might not mind the "hang" UI for 10 seconds, but users will surely be annoyed. Also, blocking the UI thread will cause Windows to think that your app is frozen, so you'll get that nice "not responding" badge and all related stuff. This not only looks awful but also can cause various side-effects.
You should really take a look around and see what .NET offers you for such kind of problems.
Look, this is your workflow:
Print a message
Start initialization
???
Initialization is complete --> print "done"
Start operation
What is this? This is an asynchronous processing. You start an action and continue asynchronously - that means, only when the action is completed.
.NET offers you a lot of tools for that, e.g. the APM (Asynchronous Programming Model). But the most neat and powerful way for implementing asynchronous processing is the TAP - Task-based Asynchronous Programming pattern, better known as async/await.
Look, your problem can be solved with a couple of lines using the TAP:
async void StartTest_btn_Click(object sender, RoutedEventArgs e)
{
OutputText("Please Wait\r\n");
// Set_COMM_MODE will be executed on a worker thread!
// The main (UI) thread won't block. It will continue.
// But the StartTest_btn_Click method itself will pause until the task is finished.
await Task.Run(() => Set_COMM_MODE("02"));
// This line will only be executed, after the Set_COMM_MODE call is completed;
// furthermore, it will be executed on the UI thread again!
OutputText("Done\r\n");
}
You should really learn more about the modern programming techniques, which the TAP is one of.
I have a multi-threaded application, and both in the main UI thread and in other background threads, I have stop-methods that call Application.Exit().
The weird thing is that after the call, the program continues on to the next line (and then eventually exits). The obvious problem with this can be explained with the simple code below:
if (XYZ) Application.Exit();
Globals.Instance.LoggerDictionary["ApplicationLog"].Log("Bla bla...");
And this:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
var button = sender as Button;
if (button != null && string.Equals(button.Name, #"CloseButton"))
{
//FormClosing event raised by a user created button action
}
else
{
//FormClosing event raised by program or the X in top right corner
Globals.Instance.LoggerDictionary["ApplicationLog"].Dispose();
Globals.Instance.LoggerDictionary["OtherLog"].Dispose();
MemoryHandler.Instance.Dispose();
}
}
As seen the FormClosing method ensures that cleanup of unmanaged resources is done. So, in many cases the application moves on to the line below Application.Exit(), and, in the example above, try to write something to the Log, which has already been disposed by the FormClosing() method.
My question is therefore: Does Application.Exit() spawn a new thread where FormClosing() is run from? If not, then why does it continue on?
http://msdn.microsoft.com/en-us/library/system.windows.forms.application.exit(v=vs.110).aspx
Informs all message pumps that they must terminate, and then closes all application windows after the messages have been processed.
This method does not terminate the process. Instant termination is rarely a useful shutdown model because it is unclear what useful shutdown actions would be skipped.
If this method does not terminate the process then clearly your code must continue to run.
This is normal and the right way to shut down the app. If you want to skip certain logic, set a flag bool isShuttingDown and react to it.
No, it does not start a new thread. It also doesn't immediately kill the UI thread. The whole point of Application.Exit is to gracefully exit the application. All forms will be asked to be closed, resources will be cleaned up, all pumped through the main application loop. When the application loop next becomes idle, rather than waiting for more messages, it will instead stop pumping messages and the application will continue running after the call to Appliaction.Run that created the message loop in the first place. That thread can then go on to do whatever (usually end; unless you've added more code).
No it does not spawn a extra thread. Looking at the reference source inside the function it will call each form's FormClosing event, it then returns control to the caller. Once the caller completes and control returns to the message loop that is when the program will actually shut down.
All of this happens on the single UI thread.
I'm a bit stumped. I've worked with background workers before, and have them in many locations in my app. In order to show "Progress" of what is going on, but with verbiage instead of just "% complete", I've created a simple "Window". In this window, I have a simple label. Due to issues of background worker threads vs the UI thread, I can't access directly, so I have a "setter" on the Window which does nothing more than
public string NewStatus
{
set { this.lblWindowShowStatus.Content = value; }
}
So, when by BGW "ReportsProgress" and passes whatever message to the window's "NewStatus" setter (so it is operating on the proper UI thread). This all works perfectly and no problems... provided the background worker is doing something within the C#.Net app.
Next... I need to run a DOS command with some command arguments, but do not want to see the ugly black window. So, from the other threads, I've found and worked THAT part out perfectly. No problems. So, at this point, all syntax and functionality between the two elements (window with background worker refreshing the status) and (calling a DOS command to run some parameterized utility).
NOW, the problem. Trying to get the window status to refresh while running the DOS command. So, this exposed me to "OutputDataReceived" to redirect the output and capture line at a time (which is perfect).
oDOSCall.StartInfo.RedirectStandardOutput = true;
oDOSCall.OutputDataReceived += DOSOutputHandler;
// start for process and wait asynchronously until finished...
oDOSCall.Start();
// NOW begin async read of output stream
oDOSCall.BeginOutputReadLine();
oDOSCall.WaitForExit();
Then in the DOSOutputHandler, I have
private void DOSOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
// Collect the sort command output.
if (!String.IsNullOrEmpty(outLine.Data))
{
string txtData = outLine.Data;
// pass on to the WINDOW directly
oWnd.NewSubStatus = txtData;
}
}
This just hangs and never performs the update to the window on the UI thread. So, I think... try wrapping the DOS command into a BGW thread... So, I do... almost all identical, SO, from the DOS command that I'm capturing its output stream, the BGW thread gets it. I then try to forward that string value up to the Window status, but it appears to hang... Almost like the UI thread, calling a BGW thread, which is calling a Process (new thread of its own) doesn't want to play well.
Any ideas?
Instead of using the stream, try using the output events !
See my answer here to my own question:
Controling cmd.exe from Winforms
I'm using the following method to show a modeless Message Box.
public void ShowMessageBox(string Message)
{
var thread = new Thread(
() =>
{
MessageBox.Show(Message);
});
thread.Start();
}
The "() => {...}" is something I've never seen before. What is the name for this code pattern?
Also, thread.Start starts the thread, and it automatically closes once the "()=>{...}" method completes (when the Message Box is OK'ed), right? If so, can you please point me to some official documentation saying that the thread closes automatically?
Thanks!
It's the lambda operator, and read as "goes to". MSDN has a good intro: Lambda Expressions (C# Programming Guide)
One concern with your example is that you're spinning up a new thread to update the UI, the UI is intrinsically single-threaded, so background updates are generally the wrong thing to do (unless you're manually/explicitly checking InvokeRequired and calling Invoke() as needed.
Regarding the UI threading...
In WinForms every Form or Control is created on a particular thread (the "UI Thread"), and you can think of that thread as owning that control (not exactly correct, but a good way to conceptualize it). Updating the UI from that thread is safe, updating the UI from another thread runs the risk of collisions and corruption and all the usual risks of parallel/async programming.
...So... how do you safely update the UI from a background thread without blocking the UI? In short--you can't--the best you can do is block it for the bare minimum required to update the UI. This is where InvokeRequired and Invoke() come in...
Here's a sample: you should be able to drop this into the code-behind of a new form with a button and textbox.
To use:
Try commenting out either the call to SetTextAsyncSafe() or SetTextAsyncSafe() -- running both could confuse you since they won't necessarily execute in the order they're called (they're running async, remember?).
Then set a breakpoint on SetText(). You should see the "safe" call will actually call the method twice--the first call will detect InvokeRequired and will call the method a 2nd time for the correct thread by Invoke()'ing to it.
You should see an Exception thrown when SetTextAsyncUnsafe() actually gets to the textBox1.Text = value; statements. The exception will be an InvalidOperationException with a message stating "Cross-thread operation not valid" -- you can google this term for more details.
The code:
private void button1_Click(object sender, EventArgs e)
{
SetTextAsyncSafe("This update was made from the UI Thread by using Invoke()");
SetTextAsyncUnsafe("This update was made directly from the background thread and can cause problems");
}
private void SetTextAsyncUnsafe(string value)
{
new Thread(() => SetText(value, false)).Start();
}
private void SetTextAsyncSafe(string value)
{
new Thread(() => SetText(value, true)).Start();
}
private void SetText(string value, bool checkInvokeRequired)
{
if (checkInvokeRequired)
{
if (InvokeRequired)
{
Invoke(new Action(() => SetText(value, checkInvokeRequired)));
return; // early exit
}
}
textBox1.Text = value;
}
That is a Lambda. In this case, you're using it to create a new anonymous method that will be run when the new Thread is started.
It's the (near) equivalent of:
public void ShowMessageBox(string Message)
{
var thread = new Thread(ShowBox);
thread.Start(Message);
}
public void ShowBox(object message)
{
MessageBox.Show(message.ToString());
}
This is called a Lambda Expression. You can read more here.
Lambda expression, C# version 3 feature.
Don't use this code. A message box needs a parent window, something it can make sure to be on top of. It can normally find a parent by itself by iterating the windows that were created on the same thread. Not in this case though, there are no other windows, it has to pick the desktop window as the parent.
That will go wrong badly when the user is working in an app window or switches focus to another app, the message box disappears behind the foreground window. There is no obvious way for the user to tell that it is there, she'll just loses sight of it. It could be hours, if not days, before she finds it back. That thread is meanwhile consuming resources badly, you would probably never consider it if you knew that this message box requires a megabyte of memory. In extreme cases, you'll crash the program with OOM.
The common alternative in Windows UI programming is a balloon tooltip provided by a NotifyIcon. Or your own form with the TopMost property set to True so it cannot easily get lost. Also allows you to control the position, important for "non-modal" notifications that should not get in the way. Set that form's ShowWithoutActivation property to true in the form constructor so it doesn't steal the focus.
Its a statement lambda.
Yes, thread is active as long as this anonymous method is running. Since after MessageBox.Show() there is no other statements, thread will exit, and this must be true... if you are in doubt add this before start:
thread.Name = "LALALA";
And then debug your app. When the message box apear, pause execution, go to Threads View and you will see LALALA running. Click OK and pause again, there should be no "LALALA"... =)