When I run the program in one fast computer, the ProgressBar and a Label(that write the progress too) gets perfectly updated. When I run it on a weak computer (like PIV or old c2d) the ProgressBar and the form stay freezed (but the program run until it finishes).
How can I resolve that? With background worker?
If you're using a progress bar, I'm guessing whatever the task is is definitely long enough to warrant a background/worker thread. There are lots of options (BackgroundWorker, spinning up your own thread, etc). BackgroundWorker is probably the easiest.
Yes, you should put your processing into a background thread. Using a background worker is a good idea, because you can simply update the controls from its ProgressChanged event.
There are some methods that allow the UI to be refereshed in long-running tasks.
1- run the task in another tread/in an anychronous method call and then using this.Invoke to change the progressbar.
2- Force the UI to refresh at some points in the task by calling Application.DoEvents() in winforms for instance.
Related
I am creating winform to process (convert txt files to tiff) large amount of files. I put all the code behind a button (btnProcess). Is this a good idea? It works but I noticed when I go away from the winform and come back to this I see blank window until the process is complete. I heard about background worker. what is the purpose of background worker?
What you need here is multi-threading. That means that two (or more) threads of code would run in parallel. One of them would be the UI thread, the one responsible for drawing the window. In your case you are running your code in the UI thread and thus blocking the UI rendering while your code is running.
The purpose of the BackgroundWorker is to start an operation on a new thread and is what you need.
BackgroundWorker class
The BackgroundWorker class allows you
to run an operation on a separate,
dedicated thread. Time-consuming
operations like downloads and database
transactions can cause your user
interface (UI) to seem as though it
has stopped responding while they are
running. When you want a responsive UI
and you are faced with long delays
associated with such operations, the
BackgroundWorker class provides a
convenient solution.
The page I linked above contains a complete BackgroundWorker example.
It depends on your application. If this is a single purpose application that is not extremely long and the only problem is the screen doesn't paint. Which is what it sounds like to me, just throw an Application.DoEvents into the loop and be done with it.
I have been googling around for about an hour, and I still don't found any solution.
I simply try to set the maximum value of a progressbar from another thread. So I found the Control.Invoke method. I've been going ahead and implement it:
Now, when I debug my App it simply stucks at the this.Invoke line. The UI comes up, and it is frozen. So I was going ahead and google that out, and it told me to use this.BeginInvoke(). I implemented it, and I was fine, the UI don't freeze.
Thats quiet nice, but in fact the maximum value of my progress bar didn't change :(
What am I doing wrong?
EDIT: Maybe that helps: I am using Parallel.Invoke(); to manage my thread ...
Control.Invoke will only block when it is called on a worker thread and the UI thread is blocked.
The code you posted is correct. You must be blocking the UI thread somewhere else.
I use something similar below in my application which I use to update the actual value for the progress bar. I have changed it a bit from your example. Give it a whirl and see if it helps :)
public void SetMax(int value)
{
if (this.ProgressBar_status.InvokeRequired)
{
this.BeginInvoke(new Action<int>(SetMax), value);
return;
}
this.ProgressBar_status.Maximum = value;
}
I would suggest it is better to use Background worker component which supports reporting progress in the progress bar including other features rather than to call invoke and BeginInvoke. You can find more details about background worker at below MSDN link:
http://msdn.microsoft.com/en-us/library/c8dcext2.aspx
I had the same problem and thanks to Nicholas' answer I realised I had fallen into the same trap in a GUI app to debug a class used in a windows service. The service class runs most of it's code in a thread. The thread was calling back to a logging procedure when it stopped. I was stopping it using a button, and the logging used invoke to update a textbox. The problem was so simple I kicked myself - the invoke was waiting for the button-click to finish, which was waiting for the class to stop which was waiting for invoke to log that it was stopping (repeat until task-manager end process). Solved by creating a thread in the stop button click, with a threadproc to stop the service class. This meant I had to put more code to update form after the stop in another invoke from the new thread, but that worked ok as it wasn't waiting for the main form thread.
In my case, mistake was using join() after starting thread.
join() prevents main thread from execution of codes before child thread completion.
I removed join() command and moved codes after join() to thread and everything worked fine.
I am currently working with threading and backgroundworker in c#. The problem im having is that this. Say i have a main thread for user interaction and a worker thread to process txt files(various editing operations). Then after the backgroundthread runs its contents once, i have a timer start that performs another set of operations. I want these new operations that the timer runs ever x minutes to be run in the same background thread without running the previous txt related operations it ran before the timer started. How can this be done?
You should just use a System.Timers.Timer, which will run its callback on a thread pool thread.
It shouldn't matter which specific thread you run on (as long as it's not the UI thread).
If, for some reason, it does matter (eg, if you're using a single-threaded COM object), you'll need to make a dedicated thread that waits for things to do using a thread-safe queue of delegates.
You want to use an Event Driven method to execute function calls on your worker thread from your UI thread. The way to accomplish this is using BeginInvoke, you can read more about how to use it here: http://www.dreamincode.net/forums/topic/35616-cross-thread-communication-in-c%23/
Add a while loop to the end of your background worker:
while(!stop) { Thread.Sleep(yourIntervalinMilliseconds); ... }
I'd create a stop bool somewhere that the thread looks at when you want it to kick out.
Why does the ProgressBar update in theoretically blocked UI thread?
In simple app I have a ProgressBar and a Label. I run a time-consuming method in UI thread which tries to update the ProgressBar and the label. This is not supposed to work, because of blocked UI thread. But the ProgressBar is updating!
Until I do anything on the form and it freezes, the ProgressBar updates (the label does not).
Why is that?
Example code (put a Button, a ProgressBar and a Label on form):
private void button1_Click(object sender, EventArgs e)
{
while (true)
{
progressBar1.Value += 1;
label1.Text += "1";
Thread.Sleep(100);
}
}
ProgressBar is updating, Label is not. My question is not how to make label update aswell, but why ProgressBar is updating. I DO know about Threads, DoEvents, async/await and that is not the answer.
I think it's hard to answer this completely without disassembling a bit of Windows, which is too much work for me right now.
But basically, when you set .Value on an WinForms ProgressBar control, it does little more than call SendMessage with message 1026 (PBM_SETPOS), which tells the Windows progress bar to set its position.
I would conclude that the Windows progress bar redraws itself synchronously in response to PBM_SETPOS as well as in response to WM_PAINT. Or perhaps it's running a timer on another thread in order to do the fancy glare animation, and that's able to redraw the control without waiting for a paint message.
Either way, it's just Windows internals you're seeing - and drawing stuff outside WM_PAINT handlers is not that an unusual technique, even though it's not the textbook way of doing things.
Actually, looking at the docs for PBM_SETPOS ( http://msdn.microsoft.com/en-us/library/bb760844(v=vs.85).aspx ) it's documented as causing a redraw - I guess this is done deliberately to help the lazy/inexperienced to get blocking progress bar updates to work without all usual hassle of doing it properly.
There are different approaches to answering your question. Let me explain. If you are running a lengthy task where the user has to wait to proceed, it actually doesn't matter whether you are running on the UI thread or not. Either way, the user has to wait for the task to complete to proceed, so they cannot use the application anyways.
However, in operations where you may want the user to interact with different parts of the application while the task is running, you create a worker thread to perform the said task. You need understand that the main UI thread is for, well, processing the UI. Painting a progress bar is part of the UI. The designed architecture of WinForms/.NET is that you create a background thread by means of the BackgroundWorker class, or wireup raw threads on your own. Its by design.
This all, however, will change drasitcally with C# 5.0 with the async and await keywords, as well as Task objects. You can search up TechDays 11 on channel9, or visit my Facebook (Posted about it a few posts down).
You can, to help remedy your situation if you feel inclined to keep your operation on the UI thread call Application.DoEvents() in your task to keep the Windows Messages flowing, or you can do it the right way and actually implement threading properly. Its very easy to wireup using the Thread class, a delegate, and invoking, and even easier to use a BackgroundWorker which was pretty much architected with the sole purpose of performing a task on another thread and reporting a 0/100% progressional value.
Sometimes I saw that when I call a method from my form to do something that my UI freezes. How to solve this problem? If I call that method in separate thread then problem will be solved?
If I call method in separate thread like the code below
new System.Threading.Thread(delegate()
{
HeavyMethod();
}).Start();
does this solve my problem or is there any better solution?
Call the method on a Background Worker would be the best solution.
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
Doing that you can control when things get updated (using the Report Progress Feature) and allow you to cancel the work.
Also, make sure that whatever resources you manipulate in the backgroundWorker1.RunWorkerAsync(); are properly shared. You can get into what is called "Race Conditions" which causes your output to be non-determanistic (e.g. you won't get the same results every time you run the method)
For a good walk through on Multithreading and shared resources, see this link:
http://www.c-sharpcorner.com/uploadfile/mgold/multithreadingintro10062005000439am/multithreadingintro.aspx?articleid=920ecafc-e83b-4a9c-a64d-0b39ad885705
If you are calling your method in response to an event, then by default the method will be running on the GUI thread (the thread that the runtime uses to handle all user events). If that method is huge and/or heavy, then it will "freeze" the UI as you describe.
Making it run on a separate thread is a viable solution for many of these cases.
There are cases, however, when you'll actually want the UI to "block" (for example, if you are updating a lot of controls, you don't want the user to mess with them in the meanwhile). For such cases, the sanest approach is to pop up a modal "wait" dialog.
Since it is C# 2.0, I suppose it is WinForms. Don't hold up the UI thread with CPU-bound code.
You can spawn a new thread to run your CPU-bound code, but you have to be careful not to access WinForms controls, especially not to update control properties. Many WinForms controls can only be accessed/updated from the UI thread. Check the InvokeRequired field to see if you need to marshal (i.e. use Invoke) the call from another thread back to the UI thread.
Also consider using the ThreadPool instead of creating a new thread.
That is correct, If you move the heavy processing off of the UI Thread then it should free up the UI to redraw. For what you want to do your implementation should work just fine. Although ThreadPooling or BackgroundWorker would be the suggested implementations (http://msdn.microsoft.com/en-us/library/system.threading.threadpool(v=VS.80).aspx), (http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx).