How to make multiple labels appear at different times C# - c#

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

Related

What does messageBox.Show() do in order to stop the execution of a UI thread?

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.

Application Freeze in loop when using Sleep

I have an application that I made to connect to a device using telnet, the application freeze/crash when I started it .. I have System.Threading.Thread.Sleep(3000); in couple locations of the application. I was wondering, is there a way to have the application active and buttons are useable but the some operations are only impacted by the sleep operation?
Thanks in advance.
Don't use Thread.Sleep, especially on the UI thread. This will cause a hang - by design.
Since you're using .NET 4.5, you can use await Task.Delay(3000); to asynchronously "sleep", which won't block the UI. However, this is typically a sign of a poor design - "waiting" is something that really shouldn't need to happen in a UI application in general. There are typically better approaches, such as using await on the asynchronous operation for which you're waiting, etc.
This requires a bit of an explanation. There are some threads that are special in this case the ui thread where the rendering of your Ui happens and the events from the input devices are handled. If this thread spends time doing any calculations windows will state that your application has frozen. Since you are using Thread.Sleep on it you get this result.
Articles to understand the problem
http://msdn.microsoft.com/en-us/library/ms741870(v=vs.110).aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/dd744765(v=vs.85).aspx
Recommended Solutions
On the Button press dispatch a thread that goes and does the work that you need to happen. On the meantime change the cursor for the mouse to indicate that work is happening or show a progress bar. Once it finishes you can fire(dispatchet) an event that changes the ui.
I would do something similar to:
// The Work to perform on another thread
ThreadStart start = delegate() { // ... // This will work as its using the dispatcher
DispatcherOperation op = Dispatcher.BeginInvoke( DispatcherPriority.Normal, new Action<string>(SetStatus),
"From Other Thread (Async)");
DispatcherOperationStatus status = op.Status; while (status != DispatcherOperationStatus.Completed) { status = op.Wait(TimeSpan.FromMilliseconds(1000));
if (status == DispatcherOperationStatus.Aborted)
{ // Alert Someone } } }; // Create the thread and kick it started! new
Thread(start).Start();
More Examples at:
http://msdn.microsoft.com/en-us/magazine/cc163328.aspx
If you are calling sleep within your application it will do just that. If you do not want your application to hang, you will need to create a new thread that does whatever monitoring and waiting you want it to do, if a particular condition you are looking for is met, then use a callback to your parent thread to perform whatever task you want to do.

Why is this async method blocking the UI thread?

I am struggling with an issue which is raised by this piece of code:
private int FPS = 60;
void WebView_LoadCompleted(object sender, NavigationEventArgs e)
{
WebviewContentWorker();
}
private async void WebviewContentWorker()
{
WebViewBrush wvb = new WebViewBrush();
wvb.SetSource(WebView);
wvb.Redraw(); //we must redraw at least once before collapsing the WebView
WebView.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
while (true)
{
webViewContent.Background = wvb; //webViewContent is a canvas
await Task.Delay(1000 / FPS);
wvb.Redraw();
}
}
What I'm trying to achieve here is to find a workaround for XAML's WebView which I find very sloppy. I want to be able to draw things on top of it but I can't so what I'm basically doing is taking snapshots of the WebView (using the WebViewBrush) repeatedly (based on the int FPS field) and then setting the Background property of the canvas named "webViewContent" with this snapshot. The aim is to have animations displayed on the canvas while still being able to draw on top of it (if I don't do these fast snapshots, the canvas will display a still image).
It is working fine now (I successfully redirect any Tapped event to the inside of the WebView so that clicks on buttons/links/... are properly handled) but it is somehow laggy. The slow bit being wvb.Redraw() I was wondering how I could improve the performance of my thread. It looks like the UI is responsive during the Task.Delay but is blocked otherwise...
Any input/advice is very welcome!
Edit:
Here is how I timed the Redraw call (which I believe is what causes the problem since removing it makes the application very responsive):
while (true)
{
webViewContent.Background = wvb;
await Task.Delay(1000 / FPS);
sw.Reset();
sw.Start();
wvb.Redraw();
sw.Stop();
System.Diagnostics.Debug.WriteLine(sw.Elapsed.TotalMilliseconds);
}
Which gives me these results in the output window:
0,094
0,058
0,041
0,053
0,057
0,038
0,032
0,033
0,032
0,038
0,035
0,03
0,042
0,028
0,044
0,031
0,033
0,029
0,034
0,03
0,052
0,029
So not so much after all...
It looks like the UI is responsive during the Task.Delay but is blocked otherwise...
Well yes. That's exactly what's happening. Task.Delay is the only chance you're giving the UI thread to work. Your asynchronous method is executing on the UI thread - as soon as the "delaying" task completes, you'll end up with a continuation waiting to execute on the UI thread which will redraw and then delay again.
Fundamentally, if your Redraw method is too slow to be called ~60 times per second, you need a different approach.
It's very important to understand that async doesn't put the method onto a different thread - it just allows you to act asynchronously. (Your description and title suggest that you expected your method not to be using the UI thread for any significant time.)
Additionally, as Stephen Cleary says, using a DispatcherTimer is a generally-better way of executing code periodically on the UI thread.
Task.Delay is not particularly efficient for repeatedly doing many short timeouts. You'll generate a lot of garbage.
I would recommend using a dispatcher timer or similar for this scenario.

Why is this sequential operation not being executed?

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.

Control.Invoke() hangs application

I'm showing an animation while my control is loading the data. When the thread finishes, I hide the animation and show the control. So I'm executing this code from a thread:
protected void InvokeEnableBackControl()
{
if (this.InvokeRequired)
{
this.Invoke(new OpHandler(EnableBackControl));
}
else
{
EnableBackControl();
}
}
Sometimes, when I execute this code, the main thread gets hanged in the following code:
protected virtual void EnableBackControl()
{
if (overlayAnimation.TargetControl != null)
{
overlayAnimation.TargetControl.BringToFront();
}
overlayAnimation.SendToBack();
overlayAnimation.Enabled = false;
overlayAnimation.Visible = false;
}
I'm not sure if it's hanged setting the Enable or Visible property. Do you know any circumstance that may hand the application calling these properties from a Control.Invoke?
Note that Control.Invoke is synchronous, so it will wait for EnableBackControl() to return. Consider using Control.BeginInvoke, which you can "fire and forget."
See this answer: What's the difference between Invoke() and BeginInvoke()
I've run into problems before when I'm executing .Invoke on a background thread while my main thread is still busy - this gives the impression that the app is hung, because the .Invoke just sits there, waiting for the main thread to respond that it's paying attention. Possible causes:
Your main thread is blocked waiting for something
Your main form currently had a modal dialog up, so it's not listening to new requests
Your main thread is spinning, either continually checking if something is finished or doing new work. In my case, the main thread spent the first minute spinning up background threads in a tight loop, so it wasn't listening for any .Invoke requests from background threads.
When you attach the debugger, pay special attention to what your main control MessagePump thread is doing - I suspect its lack of attention is the cause of your trouble. If you identify that it's a tight loop in your main thread that's not responding, try inserting a .DoEvents in the loop, which will pause execution and force the main thread to empty the message pump and route any outstanding requests.
Run in debug, make app hang and then pause debug in Visual Studio and inspect threads.
What I discovered is that the actual drawing/painting of controls can be quite slow, esp if you have a lot of them and/or use double buffering for smooth refresh. I was using BeginInvoke to update a listview control from data I was receiving from a socket. At times the updates were happening so fast that it was freezing the app up. I solved this by writing everything I received in the sockets async receive to a queue, and then in a seperate thread dequeuing the data and using BeginUpdate and EndUpdate on the listview and doing all the outstanding updates in between. This cut out a ton of the extra redrawing and made the app a lot more responsive.
You have to use BeginInvoke inested Invoke see this Link

Categories