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.
Related
The title sounds like some easy well-known problem, but please check out this:
I've got some WPF window that handles a list of Threads and shows ProgressBar for each Thread. The invoked GUI refresh is working for most threads showing right number of percent and also for unknown progress the IsIndeterminate state is animated. After the thread is done some animation fades out the ProgressBar.
However, for some of my heavy tasks the ProgressBar is not visually updated. For example, the IsIndeterminate state refreshes only if I force the GUI to redraw by some mouseover events or by moving the form. The fade out animation shows the same problem.
I think this is no usual stucking because the UI thread is not blocked by further operations (there's only one invoke setting IsIndeterminate = true). Until now, I wasn't able to find out what's the different between heavy tasks that result in this behavoir and tasks that do not.
Please notice that the replacement of the Thread by a BackgroundWorker shows exactly the same problem (I'm also not sure why people say BackgroundWorker will not freeze the GUI but Threads allegedly do - this seems not entirely right). Please also notice that although the thread is paused by Thread.Suspend() (yes, I know it's obsolete but this is an essential feature I need, since the task content is unknown) the GUI will not show up the IsIndeterminate animation if no other GUI element forces the refresh of the window.
Any ideas what that problem might be and how to fix it? I just need the usual refreshing rate for drawing animated controls...
Im working on a reporting system, a series of DocumentPage are to be created through a DocumentPaginator. These documents include a number of WPF components that are to be instantiated so the paginator includes the correct things when later sent to the XpsDocumentWriter (which in turn is sent to the actual printer).
My problem now is that the DocumentPage instances take quite a while to create (enough for Windows to mark the application as frozen) so I tried to create them in a background thread, which is problematic since WPF expects the attributes on them to be set from the GUI thread. I would also like to have a progress bar showing up, indicating how many pages have been created so far. Thus, it looks like Im trying to get two things to happen in parallell on the GUI.
The problem is hard to explain and Im really not sure how to tackle it. In short:
Create a series of DocumentPage's.
These include WPF components
These are to be created on a background thread, or use some other trick so the application isnt frozen.
After each page is created, a WPF ProgressBar should be updated.
If there is no decent way to do this, alternate solutions and approaches are more than welcome.
You should be able to run the paginator in a background thread as long as the thread is STA.
After you've set up your thread, try this prior to running it.
thread.SetApartmentState(ApartmentState.STA);
If you really must be on the GUI thread, then check out the Freezable class, as you might have to move the objects from your background thread to the GUI thread.
If the portions that require the UI thread are relatively small, you can use the Dispatcher to perform those operations without blocking the UI. There's overhead associated with this, but it may allow the bulk of the calculations to occur in the background and will interleave the work on the UI thread with other UI tasks. You can update the progress bar with the Dispatcher as well.
My guess is that everything that is time-consuming to create is within your Visual. If so, there is an easy solution: Don't create actual DocumentPage objects and their associated Visuals until DocumentPaginator.GetPage() is called.
As long as the code that consumes your document only requests one or two pages at a time there will be no performance bottleneck.
If you're printing to the printer or to a file, everything can be done on a background thread, but if you're displaying onscreen you only need to display a few DocumentPages at a time anyway. In either case you won't get any UI lockups.
The worst case scenario would be an app that displays pages in a thumbnail view. In this case, I would:
The thumbnail view would bind its ItemsSource to a "RealizedPages" collection which initially is filled with dummy pages
Whenever a dummy page is measured, it queues a dispatcher operation at DispatcherPriority.Background to call DocumentPaginator.GetPage() and then replace the dummy page in the RealizedPages collection with the real page.
If there are performance concerns even with realizing a single page because of the number of separate items, this same general approach can be used within whatever ItemsControl on the page has the large number of items.
One more note: The XPS printing system doesn't ever process more than one DocumentPage at a time, so if you know that's your client you can actually just keep returning the same DocumentPage over and over again with appropriate modifications.
Elaborating further on Ray Burns' answer: Couldn't you have your dataprocessing done in a class on a background thread and then databind the DocumentPage's properties to this class when the processing is done?
A little late to the game on this one, but I just worked out a solution to this so I thought I would share. In order to display the UI elements they have to be created on the UI thread on which they will be displayed. Since the long running task is on the UI thread, it will prevent a progress bar from updating. To get around this, I created the progress bar on a new UI thread and created the pages on the main UI thread.
Thread t = new Thread(() =>
{
ProgressDialog pd = new ProgressDialog(context);
pd.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
pd.Show();
System.Windows.Threading.Dispatcher.Run();
});
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
Action(); //we need to execute the action on the main thread so that UI elements created by the action can later be displayed in the main UI
'ProgressDialog' was my own WPF window for displaying progress information.
'context' holds the progress data for my progress dialog. It includes a cancelled property so that I can abort the action running on the main thread. It also includes a complete property so the progress dialog can close when the Action has finished.
'Action' is the method used to create all the UI elements. It monitors the context for the cancel flag and stops generating the UI elements if the flag is set. It sets the complete flag when it is done.
I don't remember the exact reason I had to set Thread 't' to an STA thread and IsBackground to true, but I am pretty sure it won't work without them.
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
...or...
"What evil in the depths of WPF have I awoken?"
I'm creating a Canvas on a background thread and rendering it to a bitmap. I've had this working in production code for over a year now without problems. I do the following:
create a Canvas object
create a new NameScope object
assign that NameScope to the Canvas
draw whatever I want on the Canvas
call canvas.Measure() with the Canvas's size
call canvas.Arrage() with the Canvas's available rect
call canvas.UpdateLayout()
render the Canvas
In the draw step, I have always just called canvas.Children.Add() to put UIElements onto the Canvas. This has always worked.
Now, for some inexplicable reason, in one specific case in the application I'm working on, the call to canvas.Children.Add() hangs indefinetely, blocking my background thread. I can't think of anything I'm doing differently between the code that has been working for over a year, and this one specific case.
Can anyone suggest possible reasons why a call to canvas.Children.Add() would hang like this?
Edit: The background thread is an STA thread (the background thread processing model was put in place because I couldn't process images using WPF on a MTA thread), so the thread apartment model shouldn't be the culprit.
Edit #2: While I understand why people are suggesting I try Dispatcher.BeginInvoke() from my background thread, I don't like that option for two reasons:
I want my background thread processing to be synchronous on that thread. My background thread has a queue that other threads submit image jobs to, and my background thread processes each job as it gets to them. Using Dispatcher.BeginInvoke() adds another layer of complexity that I'd rather avoid.
I've never needed to until now. Doing this background processing synchronously on my background thread has just plain worked. I'm trying to determine what could possibly be different about this bizarre edge case that causes this code to not work. If I can't get it to work, I'll end up rewriting this processing code without WPF, which I'd also rather avoid.
What apartment model are you using for your background thread?
I believe WPF needs to run on the STA thread. When you spawn the background thread, try settings it's apartment to STA.
Update:
If the STA thread is not the problem, then I would try breaking your canvas drawing up into chunks. Basically if you do a:
Dispatcher.BeginInvoke(...)
from your thread, the provided delegate gets pushed onto the back of the dispatcher queue, allowing other queued tasks to execute.
Update 2:
You could also try debugging into the source code for the Canvas object using the .NET framework reference sources. You can enable this by turning on "enable .net framework source stepping" in the debugging options under Tools->Options.
Try calling Dispatcher.Run() in the background thread.
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().