Progress bar not showing until after task is completed - winforms

I have been trying to get a progressbar set to marquee to keep moving while another function is running. After this function runs, I message would display (for this example)
The only way I was able to get this working was with a background worker and then have a
Do
Loop until condition that runs in the main form until the operation is complete followed by my message box.
This seems like a kludge way to accomplish this and a thread.start followed by a thread.join seems like a much nicer way to fix this. However, I was not able to get that working either.
I have included a small demo program if anyone is interested.
http://www.filedropper.com/progressbar
Thanks

Thread.Start and Thread.Join is not the way to do it - that basically blocks your UI thread again. Application.DoEvents isn't the way to go either - you really do want a separate thread.
You could then use Control.Invoke/Control.BeginInvoke to marshal back to the UI thread, but BackgroundWorker makes all this a lot easier. A search for "BackgroundWorker tutorial" yields lots of hits.
EDIT: To show the message when the worker has finished, use the RunWorkerCompleted event. The ReportProgress method and ProgressChanged event are used to handle updating the progress bar. (The UI subscribes to ProgressChanged, and the task calls ReportProgress periodically.)

That is not a kludge. That is the correct way of doing it; what happens with the BackgroundWorker approach? The trick is to use the ReportProgress method to push the change back to the UI (don't update the ProgressBar from the worker).

Use Application.DoEvents() in your function from time to time so that your process has some time to process his events, including redrawing the form.
Alternatively, you can use a worker thread (like a BackgroundWorker) to process your treatement, while the UI thread is displaying your progress bar.

Complementing the answer given by Marc Gravell, the BackbroundWorker has a boolean property WorkerReportsProgress, if it is set to false, when you call ReportProgress, the program will raise an InvalidOperationException

Related

Creating a thread inside a task

I have a method UploadReportNotifier() which is subscribed to an event, which is raised once i have finished uploading data to a database. In UploadReportNotifier() i want to reset some values on my GUI, ie progressbars etc, but i want there to be a time delay between doing this.
Is it possible to create a thread inside UploadReportNotifier() and call thread.Sleep, or is the timer() class more appropriate?
Thanks for your help.
If your goal is to wait a few amount of time after the execution of UploadReportNotifier before updating all your GUI controls, then a timer would be a good solution IMO.
In your UploadReportNotifier method, you can create and start a timer so your "update my GUI" code will be executed after a few time. Don't forget to stop/dispose your timer after your GUI update as you probably don't want it to be executed multiple time.
You could use the System.Windows.Forms.Timer timer class (as you may know, there are multiple timer classes available).
This one is not the most accurate one, but it executes the code in the UI thread, so you won't deal with cross-thread exceptions when modiying your UI.
I see you have found your solution. I just want to mention that in this situation you should always choose timers over Thread + Sleep, which imo is just an ugly hack that should be avoided always.
Timers are great because they are also capable of executing their code on the GUI thread, so you don't need to use Invoke or BeginInvoke. For example System.Windows.Forms.Timer for WinForms or System.Windows.Threading.DispatcherTimer for WPF.

WPF user interface with long processing execution hangs

I am extremely Sorry for this long post. I need some help on c# wpf issues. I have build a complicated UI(somehow) and there is some buttons... like start and stop and others.
When i click the start button a execution process starts with communicating with some protocol layer and others and it is a long process .. and during this process i have to show some notification UI like "Enter a Text", "Select Something" etc... this time i have to show some wpf window object... and after some time i have to automatically destroy the window and go with processing again.
At first i tried to run the execution in the Main window class. But it results that when the execution starts.. user can't click anything and ui doesno't respond rather just hangs. I investigate the problem... and found that UI is busy with processing in the execution on protocol layer so its not responding.
Here is my problem... can u give me some solution that...
i will have 2 button..start and stop
when i click the start button... a large process will start( like nested for loop with a large int which will continue for 50 seconds) in function named Processor.
at time of processing the function Processor will create several window and show them wait for 5-10 seconds and also destroy them. or user click;s on the window
And the whole time the stop button should be clickable so that when i click the stop button .. the process should be stop.
I tried this with backgroundworker, dispatcher... and using separate thread. but no luck. I guess i am missing something. because if i wait for some result showing a window..the window will definitely hang.. and if i separate them with different thread.. it will not communicate with each other. please give me some suggestions
Dispatcher is definitely the solution. You may need to set the Dispatcher Priority. Sharing some relevant code may also reveal some issues.
BackgroundWorker should do what you need. Set WorkerSupportsCancellation and WorkerReportsProgress to true.
I wouldn't suggest popping up multiple windows. Pop up one window to display status. In your loop in DoWork, call BackgroundWorker.ReportProgress. Then in the ProgressChanged event handler, update the status of the window.
To implement Stop:
In your DoWork method you need to check the CancellationPending property on the BackgroundWorker in your loop. When it is true you need to exit that method. On the stop button click, call BackgroundWorker.CancelAsync().

Need to force refresh on a WPF Label

I am making an asynchronous call to a web service. Since it might take a few seconds there is a status Label used to let the user know what's going on. But even though the call is async the first call seems to block for a few seconds and the status label takes too long to get updated. In WinForms I could force the label to refresh (using Update() I think) but not in WPF. Any super easy ways to get this working?
Thanks,
Gerry
You could move the entire call logic into a QueueWorkUserItem or BackgroundWorker block. That way the first proxy initialization would not block the UIThread (before the async. Begin/End pattern kicks in). Assuming that you are using databinding the object exposing the property bound to the Label implemented INotifyPropertyChanged everything should happen automagically.
I'd (wildly) guess that the blocking is due to the creation/initialization of the service proxy classes. If so, you could try to create the proxy earlier, or call your asynchronous web service in another thread.
The general answer to your question about refreshing controls... I have always relied on data binding to do this. That won't help though if the main UI thread is stuck doing something. And if the UI thread is stuck, I don't know that there's any way to get it to draw.
There isn't a way to tell the label to refresh that will actually work in your case. If the UI is being blocked, it won't refresh. Basically, when you actually get to the point where you update the label's text, it will show in WPF. The only possible exception that I can think to that would be if you are using a non-WPF control but even then it should work.
My suggestion would be to update the label before you perform the first action (even before variables are initialized, since this might be where the issue actually is). Here is a pseudocode example of what I mean (just in case I wasn't clear):
private void KickOffProcess()
{
label1.Text = "Processing ..."; //This is where you need to move the label update code
AsyncCall();
}

Using ProgressBar as a wait bar - how to avoid freezes?

I'm creating a custom charting control and I would like to have the possibility of displaying some sort of wait bar while other commands are running (i.e. chart is being created).
I'm using ProgressBar (System.Windows.Forms.ProgressBar in marquee mode) as a part of this control. I do not need to update the state of the progress bar, I just want it to move over and over until the chart is created.
Right now I'm using it in following scheme:
- Start wait bar (ProgressBar appears and starts running)
- Call charting methods
- When the chart is ready, the wait bar will being hidden.
The problem is: Some charting methods are really computational demanding and the wait bar freezes in such moments. How can I avoid these freezes? Should I use some kind of threading/background worker? And if yes, then what is the simplest way to do it?
Note, that I do not need to change the state of the progress bar while the chart is being prepared. I just need the wait bar to start, run during all computations and stop after that.
EDIT
OK, as suggested, I created a separate thread for these demanding computations to avoid freezes.
But how to wait for a thread to finish and do not freeze the GUI?
I tried, as suggested here, something like that:
Thread t = new Thread( () => { DoSomeLongAndDemandingTask(withParameters); });
t.Start();
t.Join()
// do something that needs to be done after thread finishes
InvokeMeAfterThreadFinished();
But it freezes the GUI. Is there any other way to avoid these freezes?
You've answered your own question - typically the answer is to move the computation onto a background thread. There is a WinForms component called the BackgroundWorker, does a lot of the lifting for you:
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
http://dotnetperls.com/backgroundworker
Note that you won't be able to access UI components from the background thread, you need to Control.Invoke onto the UI thread to get access to UI controls. This is heavily talked about (and solutions provided) on the net so Googling will be easy for this.
Alternatively, sometimes a background thread is unworkable (not sure why), so you can use Application.DoEvents() - if memory serves, this processes pending messages on the message queue (including control painting, UI updating). If you only do a little work that causes jittering, this could be a faster and simpler option - though not advised too often.
Using the BackgroundWorker class is the simplest way to perform a background computation.
However, just be careful that the charting methods you are running in the background do not update the UI. All updates to the UI itself must be performed by the UI thread. So a background thread will need to "marshall" such calls to the UI - see Control.Invoke for a starting point on that.

How to wait for a background thread/operation to complete in WPF UI code?

e.g. in Winforms I'd write...
// on UI Thread
BackgroundWorker workerThread = new BackgroundWorker();
workerThread.DoWork += new DoWorkEventHandler(LoadChildren);
workerThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(OnLoadChildrenCompleted);
while (workerThread.IsBusy)
{
Application.DoEvents();
}
In WPF what is the equivalent of Application.DoEvents in Winforms?
I have a property called Children in my ViewModel class. A HierarchicalDataTemplate has been setup to read Items from the Children property.
A TreeView displays the nodes. When the user expands a node, the children of the node are generated from the results of this property
public Node Children
{
get
{
// 1. time-consuming LINQ query to load children from a SQL DB
// 2. return results
}
}
So I'd like to run 1. on a background thread and wait for it to complete before returning the results... keeping the UI responsive.
Googling led me to this page which has uses DispatcherFrames to simulate the above method. But this seems to be too much work.. which hints at 'Am I doing this right?'
As I understand it, you've got this sort of flow:
Do some prep work (UI thread)
Do some background work (other thread)
Do some finishing work (UI thread)
You want to wait for the second bullet to finish before running the code in the third.
The easiest way to do that is make the second bullet's code call back into the UI thread (in the normal way) to trigger the third bullet to execute. If you really, really want to use local variables from the method, you could always use an anonymous method or lambda expression to create the delegate to pass to the background worker - but normally it would be cleaner to just have a "PostBackgroundWork" method or something like that.
EDIT: This wouldn't be nice for a property as you've shown in your edited question, but I'd refactor that as a request to fetch the children with a callback when it's completed. This avoids the whole mess of reentrancy, and makes it clearer what's actually going on.
Calling DoEvents on the UI thread in a loop like this is not recommended practice in WinForms or WPF.
If your application can't continue until this thread has finished its work, then why is it on another thread?
If some parts of your application can continue, then disable those bits that can't and reenable them when your completion callback is called. Let the rest of the system get on with its stuff. No need for the loop with DoEvents in it, this is not good practice.
Take a look at the community content on MSDN.
This is a good article on DoEvents.
In WPF what is the equivalent of Application.DoEvents in Winforms?
There is none built-in, but you can easily write your own. Indeed, WPF gives you more power around message processing than does Winforms. See my blog post on Dispatcher Frames here. It includes an example showing you how to simulate Application.DoEvents().

Resources