Threading not working? - c#

So! I am just playing around with progress bars in winForm but I noticed something. If I use a For statement the progress bar goes from 0 - 100 instant, even if I put a EX: Thread.Sleep(10000); It waits the time and then goes too 100%.
What am I doing wrong?
public void progressbar(object sender, EventArgs e)
{
for (int i = 0 ; i < 100; i++)
{
Thread.Sleep(10);
progressBar1.Value = i;
}
}

You're blocking the UI thread. While your event handler is running, your window can't handle any incoming window messages, so it will not update, and it will not repaint. Don't block the UI thread.

You need to update every interaction your progressbar. Note also that in your for, will go to 90 only and not to 100. Try this code:
for (int i = 0; i <= 100; i++)
{
Thread.Sleep(10);
progressBar1.Value = i;
progressBar1.Refresh();
}
EDIT:
To work you must put in some event such as the click of a button , never in a Form Load

Related

C# "Thread.Sleep" Messing My Program (Form Doesn't Show Up)

i add a loop to my program just to check something...(For verification)
for (int i = 1; i < total; i++){
for (int row = 0; row < 4; row++){
for (int col = 0; col < 4; col++){
pixel = block[i][row][col];
label1.Text = pixel.R.ToString("X");
System.Threading.Thread.Sleep(100);}}}
After Add this loop program works , but form doesnt show up. I Start Debuging and i saw that in this line it stops. Dont go any further.
Application.Run(new Form1());
Basicly begining of the program. So I isolate the System.Threading.Thread.Sleep(100);}}}
Part it is working now. Why this code is causing problem. I used the
using System.Threading.Tasks;.
Any idea or i can use other delay function... İ waiting for your help. Thank you..
You should never, ever, block the UI Thread (by means of sleeping or doing some heavy work) as the Thread can only either handle UI-Events (clicks, rerendering, resizing) or run your code, not both. In cases where you must execute some long running code from a event-handler, you can either start a new thread to do the work or run async code.
For you, something like this should work just fine:
public async void Form1_Load(object sender, EventArgs e) {
for (int i = 1; i < total; i++){
for (int row = 0; row < 4; row++){
for (int col = 0; col < 4; col++){
pixel = block[i][row][col];
label1.Text = pixel.R.ToString("X");
await Task.Delay();
}
}
}
}
While Sleep blocks the thread while it waits, await Task.Delay(); does not. It actually returns and lets the thread continue doing whatever it was doing previously and notifies the thread when it finished waiting so the thread can come back to your function later and continue running your code. (This is a simplification of how async and await works in C#)

Form freezing using BackgroundWorker

I'm working with a WinForm from which all processes that I need are steered. Now I'm trying to integrate a BackgroundWorker with a ProgressBar and a cancellation button into my code. I want it to be locally around my code and not in a separate method. To test this, a new form is created with a progress bar (not active yet) and a button to stop a for-loop. However, the code is not working (and the progress bar is not even included yet). The form freezes immediately (see image) so I can't test the cancel button. The for-loop, however, is executed and "Done: " + l.ToString() is shown. How can I solve this?
void stopMeasurement(object sender, EventArgs e)
{
stopMeas = true;
}
public void testcancel() // Test method which is triggered manually
{
int l = 0;
MetingProgress metingProgress = new MetingProgress();
metingProgress.btnCancelmeting.Click += new EventHandler(stopMeasurement);
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerSupportsCancellation = true;
worker.DoWork += (sender, args) =>
{
for (int k = 0; k < 10; k++)
{
Thread.Sleep(1000);
l++;
if (worker.CancellationPending)
break;
}
MessageBox.Show("Done: " + l.ToString());
};
worker.RunWorkerAsync();
while (worker.IsBusy)
{
if (stopMeas)
worker.CancelAsync();
}
metingProgress.Dispose();
MessageBox.Show("All done");
}
The form freezes immediately
this is because you have a while loop still running on the main thread! So the form will not be responsive. This is called buisy waiting. You will not be able to call the CancelAsync method.
One solution could be to remove the while-loop and place the cancel call into the button event code:
void stopMeasurement(object sender, EventArgs e)
{
stopMeas = true;
worker.CancelAsync();
}
What you have basically done is: you created a second cancelation token. So another possibility could be to use only stopMeas to cancel the background operation:
worker.DoWork += (sender, args) =>
{
for (int k = 0; k < 10; k++)
{
Thread.Sleep(1000);
l++;
if (stopMeas)
break;
}
string mes = stopMeas ? "Done: " + l.ToString() : "Task aborted!";
MessageBox.Show(mes);
};
EDIT: also this line:
metingProgress.Dispose();
might lead to an ObjectDisposed exception. If the background process is still running and trying to update your progressbar and you already dispose the form. You should remove this line and leave it to the garbage collector.
This code is your problem:
while (worker.IsBusy)
{
if (stopMeas)
worker.CancelAsync();
}
Your GUI-Thread is in that loop until your worker is done.
You need to make your worker instance be reachable from within the EventHandler and call worker.CancelAsync() from there.
Outside this , I personally would improve the code in 2 steps:
Move the whole BackgroundWorker into the MetingProgress class and make its constructor take a delegate for the actual work implementation.
Use TAP (Task Async Pattern) , i.e. async/await Task with Progress and CancellationToken.

Update GUI components from Begininvoke

So I have a very basic Windows Application where I want to count from 1 to 10000
and show the numbers in label:
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(() =>
{
for (int i = 0; i < 10000; i++)
{
BeginInvoke((MethodInvoker)delegate ()
{
label3.Text = i.ToString();
});
}
});
thread.Start();
}
The problem is that the label text doesn't update and shows only the last loop counter i.e. 9999. Is BeginInvoke called on UI thread? Why does not the label get updated correctly?
Thanks.
Because BeginInvoke is an asynchronous call, you're sending too many updates to the text box for it to update fast enough, by the time the text box has got around to drawing, it's already counted up to 10000!
You can synchronously update the text, that is, the calling loop will halt until the text box has updated and finished, use Invoke instead of BeginInvoke.

Can't change the text on an object?

I can't seem to change the text on any object - I've tried both labels and buttons so far. Why doesn't this work?
void Button1Click(object sender, EventArgs e)
{
for(int i = 60; i >=1; i--){
Thread.Sleep(1000);
i -= 1;
label1.Text = i.ToString();
}
}
It doesn't work because you are using a busy loop to update the text.
This code runs in the main thread, so it's busy setting the Text property for a whole minute, and can't update the user interface.
You would use a timer to update the text, so that the main thread regains the control in between changes.
Try taking out the Thread.Sleep() command to see if the label is updated. You may find that the UI thread exits the function even though you requested it to sleep.
What you can do is use a Timer control, and set the interval to 1000 (1 second). Then you can set the label1.Text to a counter or static field value (or hidden field).
As long as you stay in the Button1Click the UI thread seams to be sleeping. Delete the Thread.Sleep and you will see that the text is shown in the labels.
put Application.DoEvents(); in your code after last line, then it will work for sure.
for (int i = 60; i >= 1; i--)
{
Thread.Sleep(1000);
i -= 1;
label1.Text = i.ToString();
Application.DoEvents();
}
First of all you have to learn How to: Make Thread-Safe Calls to Windows Forms Controls.
You need to create a thread and use Invoke delegate.
Thread th = new Thread(test);
th.Start(); //start the thread
This method will update the lable.text
void test()
{
for (int i = 60; i >= 1; i--)
{
Thread.Sleep(1000);
if (label1.InvokeRequired)
{
label1.Invoke(new Action(() => {
label1.Text = i.ToString();
}));
}
}
}

C#: Wait until progressbar finished drawing [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Winforms Progress bar Does Not Update (C#)
First time asking a question here for me.
I'll try to explain my problem using this code snippet:
progressBar1.Maximum = 50;
for (int i = 0; i < 50; i++)
{
progressBar1.Value++;
}
MessageBox.Show("Finished");
progressBar1.Value = 0;
The problem with this code is that the MessageBox pops up at the time the for loop is finished, not when the progressbar has finished drawing. Is there any way to wait until the progressbar has finished drawing before continuing?
Thanks guys!
You might want to have a look at System.Windows.Forms.Application.DoEvents(). Reference
progressBar1.Maximum = 50;
for (int i = 0; i < 50; i++)
{
progressBar1.Value++;
Application.DoEvents();
}
MessageBox.Show("Finished");
progressBar1.Value = 0;
The issue here is that you are doing all of your work on the UI thread. In order to re-draw the UI, you would normally need to pump windows messages.The simplest way to fix this would be to tell the progress bar to update. Calling Control.Update will force any pending drawing to be completed synchronously.
progressBar1.Maximum = 50;
for (int i = 0; i < 50; i++)
{
progressBar1.Value++;
progressBar1.Update();
}
MessageBox.Show("Finished");
progressBar1.Value = 0;
The other methods that may work would be to use a background thread (with all of the extra Control.Invoke calls needed to synchronize back to the UI thread). DoEvents (as mentioned previously) should also work -- DoEvents will allow your window to process messages again for a time which may allow your paint messages through. However, it will pump all of the messages in the message queue so it may cause unwanted side effects.
Try the following code
progressBar1.Maximum = 50;
for (int i = 0; i < 50; i++)
{
this.SuspendLayout();
progressBar1.Value++;
this.ResumeLayout();
}
MessageBox.Show("Finished");
progressBar1.Value = 0;

Categories