C# winforms, progress bar will freeze on button click event - c#

So I have my progress bar in my form as 'Marquee' style so it should continuously run, however when I click my button so that the progress will appear, it is froze and does not move, however if I don't hide the progressbar at the start it will run normally.
I only want it to appear when the button is clicked though, any ideas around this?
public Form1()
{
InitializeComponent();
progressBar1.Hide();
}
private void button1_Click(object sender, EventArgs e)
{
progressBar1.Show();
DrawingHandler MyDrawingHandler = new DrawingHandler();
MyDrawingHandler.GetConnectionStatus();
try
{
Operation.RunMacro("shaftCheck.cs");
DrawingEnumerator SelectedDrawings = MyDrawingHandler.GetDrawingSelector().GetSelected();
if (SelectedDrawings.GetSize() == 0)
{
MessageBox.Show("Error, no drawings to export.");
}
else
{
Operation.RunMacro("ExportShaft2.cs");
}
}
catch (Exception)
{
MessageBox.Show("Error");
}
}
}

The most likely reason is that you are doing some kind of slow operation on the UI thread.
There is in most cases only one UI thread, this is the only thread allowed to update the UI, and this can only do one thing at a time. If you are using the UI thread to do some kind of processing it cannot do other things, like updating your UI.
The solution is to put all processing intensive operation on a background thread. For example with Task.Run. But you will need to ensure any called code does not trigger any UI updates.
If you just have a progress bar as part of the dialog it is fairly easy. But it results in the user being able to do other things while you are doing the processing, so you need to be super-careful that all your code is thread safe.
A safer option is usually to show a modal dialog that prevents the user from doing anything else. This greatly reduces the risk of thread safety issues. Typically it would look something like this:
var progressForm = new MyProgressForm();
Task.Run(MyWorkerMethod)
.ContinueWith(t => progressForm.DialogResult = DialogResult.OK, TaskScheduler.FromCurrentSynchronizationContext());
progressForm .ShowDialog();

Is there another property in the progressbar that is a better fit for your needs. Winforms Progress Bar Visible true false in this post it looks like you can change the visibility with the Visibility property.

Your program has only one thread that may update the UI. If you keep this thread busy doing other things, then your UI won't be updated, nor will it respond to operator input.
void LongRunningMethod() {...}
private void OnButton1_Clicked(object sender, ...)
{
this.progressBar1.Visible = true;
this.LongRunningMethod();
this.progressBar1.Visible = false;
}
While LongRunningMethod is being executed, the UI won't respond: the progressbar is not updated, the UI does not respond to user input.
There are two often used methods to solve this.
Old fashioned: use a BackGroundWorker, and let this BackGroundWorker do the LongRunningMethod. The BackGroundWorker sends events when it is finished. You can use that event to hide the progressBar again.
Modern: use async-await. Let a separate Task do the LongRunningMethod.
I won't discuss the BackGroundWorker. If you understand event handling, you will get the gist of it. I'll describe async-await instead.
What really helped me to understand async-await was this interview with Eric Lippert. Search somewhere in the middle for async await.
In this interview Eric Lippert compares async-await with a cook making breakfast. Whenever the cook has to wait for something, like a kettle of water to boil, he doesn't wait idly, no, he looks around to see if he can do something else instead, like insert bread in the toaster. He doesn't wait for the bread to be toasted, he starts scrambling eggs. Later he returns to the boiling water to make tea, or to the toaster to get the toasted bread.
Async-await is similar: whenever your thread has to wait for another process to finish, like writing a file, reading from a database or from the internet, you can let the thread wait idly until the other process completed the task. You could also let the thread do other things, like updating the progressbar and listening to user input. This is called async-await.
Whenever your thread sees an await, it does not wait idly, but it goes up the call stack and execute the code until the caller has an await, up the call stack again and execute the code until the thread sees an await, etc.
Later, when the file-write is finished, or the database data is fetched, or the internet data is downloaded, the thread (or to be precise: any thread from the thread pool) will execute the code after the await.
To be able to use async-await, do the following:
Whenever your program has to wait for another lengthy process, like the examples that I gave above, find the async version of the process: WriteAsync / ReadAsync etc
Define your method async. It is common usage to terminate the identifier of the method with Async: ReadFileAsync, GetProductsAsync, etc. This will make it possible to also have a non-async version: ReadFile, GetProducts.
Return Task<TResult> instead of TResult; return Task instead of void.
There is one exception to this rule: event handlers always return void: no one can await for the result of an event handler
Inside the async method call the WriteAsync / ReadAsync etc. Don't await until you need the results of the async action. await before your async method returns
If the return is Task<TResult>, the result of the await is TResult. If you await Task, the return is void.
So if you need to read lines of text from a file:
private async Task<List<string>> ReadFileAsync(string fileName)
{
using (TextReader textReader = new StreamReader(fileName))
{
List<string> lines = new List<string>();
string line = await textReader.ReadLineAsync();
while (line != null)
{
// a line has been read, add it to the lines, and read the next
lines.Add(line);
line = await textReader.ReadLineAsync();
}
}
}
So if the operator presses a button to read the file and to process the read lines async:
private async Task ProcessLinesAsync(IEnumerable<string> linesToProcess) {...}
private async Task ReadAndProcessFileAsync()
{
string fileName = this.GetFileName();
List<string> lines = await this.ReadFileAsync(fileName);
await this.ProcessLinesAsync(lines);
}
private async void OnButton1_Clicked(object sender, ...)
{
this.ShowProgressBar();
await this.ReadAndProcessFileAsync();
this.HideProgressBar();
}
Note that the event handler returns void instead of Task.
ShowProgressBar is a method that will initialize the progressBar before showing it using this.progressBar1.Visible = true;.
Use other thread to do lengthy calculations
Until now, the UI thread had to wait for another process to finish. Async-await can also be used if you need to do some length calculations while keeping the UI responsive. Use Task.Run to let one of the available threads in the thread pool do the lengthy calculations. Wait for it when you need the results:
private MyResult DoLengthyCalculations()
{
// Do your lengthy calculations here:
DrawingHandler MyDrawingHandler = new DrawingHandler();
MyDrawingHandler.GetConnectionStatus();
try
{
Operation.RunMacro("shaftCheck.cs");
// etc
}
private async Task<MyResult> DoLengthyCalculationsAsync()
{
MyResult result = await Task.Run( () => DoLengthyCalculations();
return result;
}
By the way: this is an example where you have an async and a non-async method: the caller can decide which one he wants to use.
The event handler:
private async void OnButton1_Clicked(object sender, ...)
{
this.ShowProgressBar();
await this.DoLengthyCalculationsAsync();
this.HideProgressBar();
}
Continue processing after the other task started
If you can do something useful instead of awaiting for the task to finish, don't await yet. Await as late as possible: only when you need the result, and before returning.
async Task DoMyWorkAsync()
{
// start reading the file. Don't await, while the file is being read,
// you can do other things:
Task<List<string>> taskReadFile = this.ReadFileAsync();
// because you didn't await, you are free to do something else as soon as
// the thread sees an await:
this.DoSomethingElse();
// you can even start a second task:
Task<MyResult> taskLengthyCalculations = this.DoLengthyCalculationsAsync();
// as soon as you need the results, await for it:
List<string>> readLines = await taskReadFile;
this.ProcessReadLines(readLines);
...
If you want: wait for both tasks to finish:
Task[] allTasks = new Task[] {taskReadFile, taskLengthyCalculations};
await Task.WhenAll(allTasks);
// you can access the return value using property Result:
List<string>> readLines = taskReadFile.Result;
MyResult lengthyCalculationsResult = taskLengthyCalculations.Result;
this.Process(readLines, lengthyCalculationsResult);

Related

how can I know if a task is completed

I have a grid that loads lots of information when a row is selected - 7 more grids and a DevExpress report need to load, and it takes a lot of time
I put all the methods into tasks to speed up the process.
But if another row is selected before the previous one finishes loading, it causes errors.
I would like to know how to check if the task is finished and the either wait or cancel the task before loading again with new data. (I am new to asynchronous programming)
This is an example of my tasks (there are 8 of them, each called one after another):
private async void LoadSSNs()
{
await Task.Run(() => grdSSNs.DataSource = ICTBLL.GetData(ID));
}
How can I change it into a Task object that I can check if complete?
You should almost never have a void return type with async/await (there are exceptions, but start with that). Your method needs to return a Task so you have something to wait on or check for completion status.
private async Task LoadSSNs()
{
await Task.Run(() => grdSSNs.DataSource = ICTBLL.GetData(ID));
}
How you determine if the task is complete depends on what you need to do. If you need to do some work while the task runs asynchronously, you could do this:
var t = LoadSSNs();
// do something while task is running.
t.Wait(); // this is one option.
if (t.Status == TaskStatus.Faulted) { } // handle problems from task.
If you have more work to do while the task completes, you could do something like this:
while(!t.IsCompleted)
{
// do some other work.
}
Again, what you do with the task is up to you; the important part is you need to return an awaitable Task from your async method.

How to keep the RunAsync() method running in the background without calling Wait()?

Trying to advance from using BackgroundWorker to Task, I am getting confused on how to keep the background job running without calling Wait().
This is the background job (simplified):
private async Task RunAsync()
{
HttpResponseMessage response = await TheHttpClient.GetAsync(Path);
if (response.IsSuccessStatusCode)
{
textBox_Response.Text = await response.Content.ReadAsStringAsync();
}
}
When the Send button is clicked, the above code should run, but because the background code has more than one await async calls, I guess that there are several Wait() calls needed:
private void button_Send_Click(object sender, EventArgs e)
{
Task t = RunAsync();
while (!t.IsCompleted)
{
t.Wait();
}
}
But this would block the GUI during the entire processing time of the background job.
How can I start the background job and return immediately from the button click handler, while allowing the background job to run all async calls?
I know how to achieve this with the BackgroundWorker, should I not use a Task here?
Event handlers are the only place you are allowed to do async void, what you do is make the event handler async and await it there
private async void button_Send_Click(object sender, EventArgs e)
{
await RunAsync();
//Do code here that needs to run after RunAsync has finished.
}
Quite often people think that async await is an asynchronous process performed by several threads, but in fact it is all done by one thread, unless you start a new thread using Task.Run or similar functions.
In this interview (somewhere in the middle. Search for async) Eric Lippert compared the async-await by the works of a cook in a restaurant. If he is toasting bread, he could wait for the bread to be ready before boiling the eggs, OR he could start boiling eggs and get back to the bread afterwards. It looks like the cook is doing two things at the time, but in fact he is only doing one thing, and whenever he has to wait for something he starts looking around to see if he can do other things.
If your one-and-only thread calls an asynchronous function, without awaiting for it. Your one-and-only thread starts executing that function until he sees an await. If he sees one, he doesn't wait until the async function completes, instead he remembers where he was awaiting and goes up in his call stack to see if his caller has something else to do (== is not awaiting). The caller can do the next statements until he meets an await. In that case control is given back up the call stack to the caller until he awaits etc. If your one-and-only thread is awaiting in all functions in the call stack control is given back to the first await. When that is finished your thread starts doing the statements after the await until he meets another await, or until the function is finished.
You can be certain that every async function has an await somewhere. If there is no await it is not meaningful to create it as an async function. In fact your compiler will warn you if you forgot to await somewhere in your async function.
In your example, you can expect an error, or at least a warning that you forgot to declare your button_send_click async. Without this the procedure can't await.
But after you've declared it async, and the button is pressed, your GUI-thread will call RunAsync where it will enter function TheHttpClient.GetAsync.
Inside this function is an await ReadAsStringAsync, and because ReadAsStringAsync is declared async, we can be certain that that function has an await in it. As soon as this await is met, control is given back to your TheHttpClient.GetAsync. This function would be free to perform the next statement if it didn't await. An example would be like this:
private async Task RunAsync()
{
var responseTask = TheHttpClient.GetAsync(Path);
// because no await, your thread will do the following as soon as GetAsync encounters await:
DoSomethingUseFul();
// once your procedure has nothing useful to do anymore
// or it needs the result of the responseTask it can await:
var response = await responseTask;
if (response.IsSuccessStatusCode)
...
The await is after DoSomethingUseful(). Therefore, the function can't continue. Instead of doing nothing until responseTask is finished, control is given back to the caller: button_send_click. If that function wasn't await it would be free to do other things. But since the button_send_click is awaiting control is given back to the caller: your UI is free to do other things.
But remember: it is always the one-and-only cook who makes your breakfast Your thread can do only one thing at a time
The advantage is that you won't run into difficulties you have with multiple threads. The disadvantage is that as long as your thread doesn't meet an await, it is too busy to do other things.
If you need to do some lengthy calculation while you don't want to be busy doing the calculation you can start a separate thread doing this calculation. This gives your thread time to do other things, like keeping the UI responsive until it needs the results of the calculations:
private async void Button1_Clicked(object sender, ...)
{
var taskLengthyCalculation = Task.Run( () => DoLengthyCalculation(...));
// while a different thread is doing calculations
// I am free to do other things:
var taskRunAsync = RunAsync();
// still no await, when my thread has to await in RunAsync,
// the next statement:
DoSomethingUseful();
var result = await taskRunAsync();
var resultLengthyCalculation = await taskLengthyCalculation;

async await: is the main thread suspended?

I was reading about async/await keywords and I've read that:
When the flow of logic reaches the await token, the calling thread is
suspended until the call completes.
Well, I've created a simple windows forms application, placed two labels, a button and a textbox and I wrote the code:
private async void button1_Click(object sender, EventArgs e)
{
label1.Text = Thread.CurrentThread.ThreadState.ToString();
button1.Text = await DoWork();
label2.Text = Thread.CurrentThread.ThreadState.ToString();
}
private Task<string> DoWork()
{
return Task.Run(() => {
Thread.Sleep(10000);
return "done with work";
});
}
What I don't understand is that when I click the button, the label1 will have the text Running and the label will have the same text only after 10 seconds, but in these 10 seconds I was able to enter the text in my textbox, so it seems that the main thread is running...
So, how does the async/await works?
here is a "screenshot" from the book:
Regards
I've read that: When the flow of logic reaches the await token, the calling thread is suspended until the call completes.
Where did you read that nonsense? Either there is some context there that you're not quoting, or you should stop reading whatever text it is that contained this. The point of await is to do the opposite of that. The point of await is to keep the current thread doing useful work while the asynchronous task is in flight.
UPDATE: I downloaded the book you referenced. Absolutely everything in that section is wrong. Throw this book away and buy a better book.
What I don't understand is that when I click the button, the label1 will have the text Running and the label will have the same text only after 10 seconds, but in these 10 seconds I was able to enter the text in my textbox, so it seems that the main thread is running...
That's correct. Here's what happens:
label1.Text = Thread.CurrentThread.ThreadState.ToString();
The text is set.
button1.Text = await DoWork();
A bunch of stuff happens here. What happens first? DoWork is called. What does it do?
return Task.Run(() => { Thread.Sleep(10000);
It grabs a thread out of the thread pool, puts that thread to sleep for ten seconds, and returns a task representing the "work" being done by that thread.
Now we are back here:
button1.Text = await DoWork();
We have a task in hand. Await first checks the task to see if it is already complete. It is not. Next it signs up the remainder of this method as the continuation of the task. Then it returns to its caller.
Hey, what is its caller? How did we get here anyways?
Some code called this event handler; it was the event loop that is processing Windows messages. It saw a button was clicked and dispatched to the click handler, which has just returned.
Now what happens? The event loop keeps running. Your UI keeps on running nicely, as you noticed. Eventually that thread ticks off ten seconds and the task's continuation is activated. What does that do?
That posts a message into the Windows queue saying "you need to run the rest of that event handler now; I have the result you were looking for."
The main thread event loop eventually gets to that message. So the event handler picks up where it left off:
button1.Text = await DoWork();
The await now extracts the result from the task, stores it in the button text, and returns back to the event loop.
async/await creates a state machines that handles the continuation for you. A very rough equivalent (without a bunch of features) is an explicit continuation method, for instance:
private void button1_Click_Continuation(string value)
{
button1.Text = value;
label2.Text = Thread.CurrentThread.ThreadState.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
label1.Text = Thread.CurrentThread.ThreadState.ToString();
DoWork(button1_Click_Continuation);
}
private void DoWork(Action<string> continuation)
{
Task.Run(() => {
Thread.Sleep(10000);
continuation("done with work");
});
}
Note that I am still using Task.Run to run on a seperate thread. Note that this version has no way of tracking progress (while the original could change the return value of button1_Click to Task to see if it has completed or not).
In addition to the above transformation the system is smart about whether a Task started on the UI thread and marshalls back to the UI thread again to ensure everything works as you expect. This is probably the main thing you didn't realize but expanding on the state machine aspect sometimes explains what asyc/await really means (instead of leaving it as mystical).
By writing await, you are saying - please stop execution of the method at this point, wait for DoWork to finish and only then continue.
Asynchronous Programming with async and await (C#) in What Happens in an Async Method section has a step by step explanation, with a picture, of what happens in a async method.
An even better explanation is at await (C# reference). Have a look at comments for WaitSynchronously and WaitAsynchronouslyAsync below.
The article also states (emphasis mine):
The await operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited task completes. The task represents ongoing work.
private async void button1_Click(object sender, EventArgs e)
{
// Call the method that runs asynchronously.
string result = await WaitAsynchronouslyAsync();
// Call the method that runs synchronously.
//string result = await WaitSynchronously ();
// Display the result.
textBox1.Text += result;
}
// The following method runs asynchronously. The UI thread is not
// blocked during the delay. You can move or resize the Form1 window
// while Task.Delay is running.
public async Task<string> WaitAsynchronouslyAsync()
{
await Task.Delay(10000);
return "Finished";
}
// The following method runs synchronously, despite the use of async.
// You cannot move or resize the Form1 window while Thread.Sleep
// is running because the UI thread is blocked.
public async Task<string> WaitSynchronously()
{
// Add a using directive for System.Threading.
Thread.Sleep(10000);
return "Finished";
}
Basically the crux is the program execution continues in synchronous manner until or unless await is encountered. once await is encountered, suppose for a Task A, the compiler will switch back to the main method which called this asynchronous method without the await keyword and will continue the program executing from calling point of Task A as compiler knows it has to wait for the completion of Task A so why not to complete its other pending task.
Here what is happening is button1_Click event is not awaited in main method so it will continue to execute once await DoWork() is encountered. And after DoWork() is completed compliler will continue to execute the further code in button1_Click

Do I need invoke to access DataGridView.SelectedRows from a async method?

I have a method like this:
async Task foo() {
foreach (DataGridViewRow row in dataGridView1.SelectedRows) {
// ...
}
}
called like this:
await Task.Run(() =>
{
foo();
});
I just noticied that code is acessing dataGridView1.SelectedRows directly, without invoke and it's working fine. Am I performing an invalid operation? Is this supposed to work or must I use invoke here?
The official answer is that is depends on who calls your foo function. Is it the main thread, or could it be a different thread?
If it is the main thread (better: the thread that created the control), than you don't need an Invoke. Async does not influence this
The following is done by the UI thread, and will work fine.
public async void Button1_Clicked(object sender, ...)
{
await Foo();
}
Quite often people think that async-await is done by several threads. But in fact it is not. A thread in an async function performs all statements until it meets an await. Instead of really waiting until the awaited function completes, it goes up in its call stack to see if it can do something else.
This is perfectly explained in Eric Lippert's restaurant metaphor (search on the page for async). Instead of waiting until the bread is toasted, the cook starts boiling eggs. But it is still the same cook.
When you see code where an async function is called without await, the thread will do the call until it meets an await and will perform the statements after the not-awaited call instead of doing nothing.
private async void Button1_clicked(object sender, ...)
{
var taskFoo = this.Foo()
// because not await: the thread will do the things in Foo until it meets
// an await. Then it returns back to do the next statements:
DoSomething();
// if this function has nothing more to do, or if it needs the result
// of Foo, await Foo:
await taskFoo;
ProcessFooResult();
}
This await for taskFoo has the effect control is given back to my caller (still the same thread), until my caller awaits. In that case control is given to his caller until await etc.
The only time a different thread is involved is when you actively start it, usually using:
var myTask = Task.Run( () => DoSomething() );
// Because there is no await, your thread will do immediately the next
// statements until an await:
DoOtherThings();
await myTask();
Now DoSomething is performed by a different thread. If you need to access UI controls you'll need InvokeRequired and Invoke.
Another helpful story about async-await: Stephen Cleary about async-await
It's because you use async and await instead of creating a new Thread / BackgroundWorker.
In my opinion it is never bad to use Invoke when interacting with Controls.

how to get a task completion notification in non gui thread

Background: I used to call a stored procedure during my Form Load. However, since this resulted in a suboptimal UI experience, I put my SP call in a task of its own inside the Shown event. Since this is typically the last event in the form display process, it resulted in a much better experience than putting stuff in the Form load event. I have:
private void MainForm_Shown(object sender, EventArgs e)
{
dbCheckTask = Task<bool>.Factory.StartNew(RunSPAndCheckStuff());
// both of below run on the GUI thread.
// if I print the thread ID in mycallback it is the GUI thread id
dbCheckTask.ContinueWith(mycallback());
// I also tried below. But obviously, that too runs on the GUI thread
mycallback(dbCheckTask.Result)
}
Because they fire on the GUI thread, my startup form paint is still neither instantaneous nor smooth. How can I get my task complete callback on a non-GUI thread without resorting to events? Whenever the task completes and if something is wrong and only if something is wrong (bool result returned false) then the user gets a message box pop. Until then he could go ahead and do other non database related stuff on the form. Please advise how I can get a task completion callback with task result in a non gui thread. Thank you
All this stuff is addressed best in the Async language extensions you can download here and has the homepage here.
It introduces the async and await keywords to C# and VB that will let you write code that switches back and forth between UI and background threads effortlessly even within a single method. The compiler will convert that to tasks, continuations, error catching etc etc transparantly without you having to worry about any of that. The example that would interest you would be this one:
public async void AsyncSwitchToCPU() {
Console.WriteLine("On the UI thread.");
// Switch to a thread pool thread:
await new SynchronizationContext().SwitchTo();
Console.WriteLine("Starting CPU-intensive work on background thread...");
int result = DoCpuIntensiveWork();
Console.WriteLine("Done with CPU-intensive work!");
// Switch back to UI thread
await Application.Current.Dispatcher.SwitchTo();
Console.WriteLine("Back on the UI thread. Result is {0}.", result);
}
public int DoCpuIntensiveWork()
{
// Simulate some CPU-bound work on the background thread:
Thread.Sleep(5000);
return 123;
}
This even has a go-live license (with some reservations from MS). Very elegant stuff borrowed from F#.
Rgds Gert-Jan
I'd use a BackgroundWorker for this, personally. One way to get your callback to run on the task thread would be to modify your method call and task creation as follows:
private void MainForm_Shown(object sender, EventArgs e)
{
dbCheckTask = Task<bool>.Factory.StartNew(() => RunSPAndCheckStuff(mycallback));
...
}
private bool RunSPAndCheckStuff(Action<bool> callback)
{
bool result = false;
// Do stuff
callback(result);
return result;
}
You should look into using the Asynchronous API's rather than calling the synchronous versions in a background thread:
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.beginexecutenonquery.aspx
The advantage to that is that no thread will be blocked, and I believe the callback will be called on ThreadPool thread, e.g. NOT on the GUI thread. From there you can marshal any GUI calls back to the GUI thread with Invoke/BeginInvoke.
Why not doing:
Task.Factory.StartNew(()=>WorkerMethod());
And define WorkerMethod() as:
void WorkerMethod()
{
RunSPAndCheckStuff(); // this blocks until finished
DoSomeMoreStuff(); // then this continuous
}
Otherwise please provide more details on what do you want to accomplish.

Categories