There were already a few similar questions on stackoverflow, but I haven't found the answer
I have an application that consists of several tab pages. On one of them I'm loading a list of a few dozen user controls at a time. Currently I'm doing it in Load event and because of that I have a small delay before this page is loaded. What I want to do is to make UI more responsive and fill the list after the page is fully loaded. Is there any way to track when the user control has fully loaded it's content?
VisibleChanged doesn't help too, because it fires before any other child control is shown. That causes some ugly visual effects when some of the child controls are still not visible when I'm starting to load control list.
EDIT
To make it more clear. I have some child controls on a page container and I have a list of custom controls I'm trying to load later. The problem with two approaches described in several answers below is that when I'm starting to load controls they do not let other child controls on the container to be shown and that is why I have those ugly effects (and I'm doing that with BackgroundWorker, but anyway it has to interact with the main thread to add controls to the list)
In order to make the UI more responsive, you should post yourself a message (Control.BeginInvoke), do one operation, post yourself another message. Then every time you do anything, the next step will get queued after all user messages, so user actions will get processed promptly.
One really nifty approach is to use yield return and let the compiler take care of all the closures logic:
IEnumerable AsyncLoadUI()
{
var p = new Panel();
Controls.Add(p);
yield return null;
for( int i = 0; i < 50; ++i ) {
var txt = new TextBox();
p.Controls.Add(txt);
yield return null;
}
}
override void OnLoad(EventArgs e)
{
IEnumerator tasks = AsyncLoadUI().GetEnumerator();
MethodInvoker msg = null;
msg = delegate { if (tasks.MoveNext()) BeginInvoke(msg); };
msg();
}
Take a look at my solution offered to another. They had a very similar issue. Wait until EVERYTHING finished its loading before doing a certain action, but not every time a form necessarily became "activated" or "shown". It involves attaching to the Load handler of your outermost control of interest. In your case, the tabbed page, but the example solution I provided was at the FORM level.
If the loading of this list incurs a small delay then doing this load on the UI thread will always make the form unresponsive no matter what event you do it in - changing this to be done after the form has loaded then it will just make the form unresponsive and visible as opposed to just causing a delay before the form is shown.
If there is no way to speed up the loading of the list then you will probably need to change your form loading logic so that the "heavy lifting" is instead done in a background thread so that the form remains responsive while the list is being populated. You should be aware that multithreaded code is more difficult to understand and when done incorrectly can produce bugs that are intermittant and difficult to debug and so you should definitely try to speed up your existing code first. That said if you can't speed up your list loading and the delay is unacceptable then there is not really any alternative.
If you do choose to load your list asynchronously (in a background thread) then the idea is to start a background thread (usually via a BackgroundWorker ) that does the hard work of preparing a list of items to be added - when this has finished (or failed) the form / list box is updated with the supplied list of items.
You should be able to find plenty of resources on how to do this on the internet that will cover this in more detail.
Related
I am reading a large Txt document into a WPF app for some serious swap/replacemnt operations. The files are actually 3D STP models so they are fairly large, but im working with them as raw text for this project. The files are read into List to avoid having to open them multiple times, and to make comparisons easier.
Anyway, I'm trying to get the listbox to scroll dynamically as lines are added to it, ala a console window so the user can see that something is happening since calculations can take a bit of time depending on filesize. I also added a progress bar to count away as the total line number is read through.
Neither my progress bar, nor ListBox seem to update as work progresses though. The final output simply lands in the listbox completed, and the progress bar goes from 0-max at the same time.
This is the gist of what I am doing, which is fairly simple:
foreach (string Line in OriginalSTPFile.Lines)
{
string NewLine = EvaluateString(Line); //string the modified to whatever here
pBar.Value++; //increment progressbar
OutputWindow.Items.Add(NewLine); //add line to the ListBox
}
I just want the listbox an progress bar to update in realtime as progress changes. I tried using:
Dispatcher.BeginInvoke(new Action(() => OutputWindow.Items.Add(NewLine));
But got the same results. Do I need a more elaborate method of multithreading here? I assumed the first method would've worked since I wasn't generating any cross-thread exceptions either.
This article will give you all the code that you need.
Backgroundworker with Progressbar
It describes very well what to do and which elements to use.
Dispatcher.BeginInvoke signals to invoke a method on the Dispatcher's thread. However, that's essentially like a post message, as it won't occur while the main thread is locked up doing work. And until the main thread is available again, it won't update the UI visually, even if you change values.
You'll need to perform the work in a background thread.
But to update the UI, you'll have to do so on the UI's main thread. This is a limitation of WPF. This is why you were directed to Dispatcher. I'm guessing someone assumed your work was already on a background thread.
To create a thread, you use Thread.Start passing it a delegate to perform. If you use a anonymous delegate or a lambda, you can refer to variables on the stack, but be aware that they will persist until the delegate quits. This is why you cannot use reference variables in a anonymous delegate.
Backgroundworker is a special type of background thread. It automates some of the expectations of a worker thread (notifying of completion, and updating on progress), but you can achieve the same results without it.
To update the UI during the thread's process, you'll need for that thread to be able to access the main UI thread. You can do that by passing it a dispatcher, referring to a dispatcher from outside the anonymous delegate, or by an object that contains a dispatcher. You can always read values from any object on any thread, so accessing the dispatcher by UIElement on another thread is fine.
To update the UI, you'll call Dispatcher.BeginInvoke with a delegate that entails the work to perform.
Here's psuedo-code of the overall scheme
class TestProgress
{
ProgressBar _ProgressBar;
void DoWork()
{
var worker = (Action)(() =>
{
int progress = 0;
// do stuff, delta is change in progress
progress += delta;
_ProgressBar.Dispatcher.BeginInvoke((Action)(() =>
{
_ProgressBar.Value = progress;
}));
});
Thread.Start(worker);
}
}
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.
We've got a Model-View-Presenter setup with our .NET Compact Framework app. A standard CF Form is implementing the view interface, and passed into the constructor of the presenter. the presenter tells the form to show itself by calling view.Run(); the view then does a Show() on itself, and the presenter takes over again, loading up data and populating it into the view.
Problem is that the view does not finishing showing itself before control is returned to the presenter. since the presenter code blocks for a few seconds while loading data, the effect is that the form is not visible for a few seconds. it's not until after the presenter finishes it's data load that the form becomes visible, even though the form called Show() on itself before the presenter started its data loading.
In a standard windows environment, i could use the .Shown event on the form... but compact framework doesn't have this, and I can't find an equivalent.
Does anyone know of an even, a pinvoke, or some other way to get my form to be fully visible before kicking off some code on the presenter? at this point, i'd be ok with the form calling to the presenter and telling the presenter to start it's data load.
FYI - we're trying to avoid multi-threading, to cut down on complexity and resource usage.
The general rule is: never do anything blocking on the UI thread
The UI in Windows (and in Windows CE as well) has an asynchronous nature. Which means that most API calls do not necessarily do whatever they're supposed to do immediately. Instead, they generate a series of events, which are put into the event queue and later retrieved by the event pump, which is, essentially, an infinite loop running on the UI thread, picking events from the queue one by one, and handling them.
From the above, a conclusion can be drawn that if you continue to do something lengthy on the UI thread after requesting a certain action (i.e. showing the window in your case), the event pump cannot proceed with picking events (because you haven't returned control to it), and therefore, your requested action cannot complete.
The general approach is as follows: if you must do complex data transformation/loading/preparing/whatever, do it on a separate thread, and then use Control.BeginInvoke to inject a delegate into the UI thread, and touch the actual UI controls from inside that delegate.
Despite your irrational fear of "complexity" that multithreading brings with it, there is very little to be afraid of. Here's a little example to illustrate the point:
public void ShowUI()
{
theForm = new MyForm();
theForm.Show();
// BeginInvoke() will take a new thread from the thread pool
// and invoke our delegate on that thread
new Action( PrepareData ).BeginInvoke(null,null);
}
public void PrepareData()
{
// Prepare your data, do complex computation, etc.
// Control.BeginInvoke will put our delegate on the UI event queue
// to be retrieved and executed on the UI thread
theForm.BeginInvoke( new Action( PutDataInTheForm ) );
}
public void PutDataInTheForm()
{
theForm.textBox1.Text = "data is ready!";
}
While you may play with alternative solutions, the general idea always remains the same: if you do anything lengthy on the UI thread, your UI will "freeze". It will not even redraw itself as you add new UI elements on the screen, because redrawing is also an asynchronous process.
Therefore, you must do all the complex and long stuff on a separate thread, and only do simple, small, guaranteed to run fast things on the UI thread. There is no other alternative, really.
Hope this helps.
If your key problem is that the form won't paint before your presenter data loading methods are completed, and you have a call to this.Show() in your Form_Load, try putting Application.DoEvents() directly after this.Show() to force/allow the form to paint.
protected void Form_Load(blah blah blah)
{
this.Show();
Application.DoEvents();
... data loading methods ...
}
No need to create another thread if you don't want to (although a couple of seconds have to be dealt with somehow).
You can use the activated event. Because it will fire when the form is activated, you need a boolean local to the form to check wether or not the form has been created for the first time.
Another option for you is to disconnect the event handler right after you finish presenting the form.
Our app's master/details view uses a datagridview as the master, and a custom control as the details view. The details view takes a long time to compute and render, making cursoring up/down the master view painfully slow.
Therefore, we'd like the details view to run asynchronously (in a separate UI thread) with change notifications from the master.
Creating a form in a separate thread is relatively straightforward, as Application.Run takes a form parameter.
Is there a way to run a winforms control on a separate thread? I'm aware that native windows in different threads can have a parent/child relationship, just not sure how to set that up using winforms.
TIA,
Updating the UI from a Secondary Thread
http://msdn.microsoft.com/en-us/magazine/cc188732.aspx
Intuitively, you also ought to be able to accomplish the same thing by using a BackgroundWorker. The BackgroundWorker is designed to update UI things like progress bars while executing stuff in the background, and it can be cancelled during its operation.
Is the slowdown caused by the loading of the data, or the population of the UI itself?
Most of the time it's the former, so if that's the case, then the logic that does the data loading should be abstracted into a different thread. The UI code can live in the main thread since updates are quick. You could use either a Thread or a BackgroundWorker in this situation. The key is to separate your data loading from your GUI population.
If you are firing off the update of the detail view in code, you can greatly improve the usability by sleeping 500ms between the time that the user selects the master record, and the time you update the detail view.
This gives the user 1/2 second to scroll to the next record without the details view updating at all.
If you're taking a speed hit during rendering, you should consider suspending layout until the form has completed updating, and then refresh the visible display once at the end.
this.SuspendLayout();
// Do control stuff here
this.ResumeLayout();
If that doesn't help, try this:
[DllImport("user32.dll")]
public static extern bool LockWindowUpdate(IntPtr hWndLock);
//
LockWindowUpdate(this.Handle);
// Do control stuff here
this.Refresh(); //Forces a synchronous redraw of all controls
LockWindowUpdate(IntPtr.Zero);
http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/8a5e5188-2985-4baf-9a0e-b72064ce5aeb
I'm currently designing/reworking the databinding part of an application that makes heavy use of winforms databinding and updates coming from a background thread (once a second on > 100 records).
Let's assume the application is a stock trading application, where a background thread monitors for data changes and putting them onto the data objects. These objects are stored in a BindingList<> and implement INotifyPropertyChanged to propagate the changes via databinding to the winforms controls.
Additionally the data objects are currently marshalling the changes via WinformsSynchronizationContext.Send to the UI thread.
The user is able to enter some of the values in the UI, which means that some values can be changed from both sides. And the user values shouldn't be overritten by updates.
So there are several question coming to my mind:
Is there a general design-guildline how to do that (background updates in databinding)?
When and how to marshal on the UI thread?
What is the best way of the background thread to interact with
binding/data objects?
Which classes/Interfaces should be used? (BindingSource, ...)
...
The UI doesn't really know that there is a background thread, that updates the control, and as of my understanding in databinding scenarios the UI shouldn't know where the data is coming from... You can think of the background thread as something that pushes data to the UI, so I'm not sure if the backgroundworker is the option I'm searching for.
Sometimes you want to get some UI response during an operation in the data-/business object (e.g. setting the background during recalculations). Raising a propertychanged on a status property which is bound to the background isn't enough, as the control get's repainted after the calculation has finished? My idea would be to hook on the propertychanged event and call .update() on the control...
Any other ideas about that?
This is a hard problem since most “solutions” lead to lots of custom code and lots of calls to BeginInvoke() or System.ComponentModel.BackgroundWorker (which itself is just a thin wrapper over BeginInvoke).
In the past, I've also found that you soon wish to delay sending your INotifyPropertyChanged events until the data is stable. The code that handles one propriety-changed event often needs to read other proprieties. You also often have a control that needs to redraw itself whenever the state of one of many properties changes, and you don’t wan the control to redraw itself too often.
Firstly, each custom WinForms control should read all data it needs to paint itself in the PropertyChanged event handler, so it does not need to lock any data objects when it was a WM_PAINT (OnPaint) message. The control should not immediately repaint itself when it gets new data; instead, it should call Control.Invalidate(). Windows will combine the WM_PAINT messages into as few requests as possible and only send them when the UI thread has nothing else to do. This minimizes the number of redraws and the time the data objects are locked. (Standard controls mostly do this with data binding anyway)
The data objects need to record what has changed as the changes are made, then once a set of changes has been completed, “kick” the UI thread into calling the SendChangeEvents method that then calls the PropertyChanged event handler (on the UI thread) for all properties that have changed. While the SendChangeEvents() method is running, the data objects must be locked to stop the background thread(s) from updating them.
The UI thread can be “kicked” with a call to BeginInvoke whenever a set of update have bean read from the database. Often it is better to have the UI thread poll using a timer, as Windows only sends the WM_TIMER message when the UI message queue is empty, hence leading to the UI feeling more responsive.
Also consider not using data binding at all, and having the UI ask each data object “what has changed” each time the timer fires. Databinding always looks nice, but can quickly become part of the problem, rather then part of the solution.
As locking/unlock of the data-objects is a pain and may not allow the updates to be read from the database fast enough, you may wish to pass the UI thread a (virtual) copy of the data objects. Having the data object be persistent/immutable so that any changes to the data object return a new data object rather than changing the current data object can enable this.
Persistent objects sound very slow, but need not be, see this and that for some pointers. Also look at this and that on Stack Overflow.
Also have a look at retlang - Message-based concurrency in .NET. Its message batching may be useful.
(For WPF, I would have a View-Model that sets in the UI thread that was then updated in ‘batches’ from the multi-threaded model by the background thread. However, WPF is a lot better at combining data binding events then WinForms.)
Yes all the books show threaded structures and invokes etc. Which is perfectly correct etc, but it can be a pain to code, and often hard to organise so you can make decent tests for it
A UI only needs to be refreshed so many times a second, so performance is never an issue, and polling will work fine
I like to use a object graph that is being continuously updated by a pool of background threads. They check for actual changes in data values and when they notice an actual change they update a version counter on the root of the object graph (or on each main item whatever makes more sense) and updates the values
Then your foreground process can have a timer (same as UI thread by default) to fire once a second or so and check the version counter, and if it changes, locks it (to stop partial updates) and then refreshes the display
This simple technique totally isolates the UI thread from the background threads
There is an MSDN article specific on that topic. But be prepared to look at VB.NET. ;)
Additionally maybe you could use System.ComponentModel.BackgroundWorker, instead of a generic second thread, since it nicely formalize the kind of interaction with the spawned background thread you are describing. The example given in the MSDN library is pretty decent, so go look at it for a hint on how to use it.
Edit:
Please note: No marshalling is required if you use the ProgressChanged event to communicate back to the UI thread. The background thread calls ReportProgress whenever it has the need to communicate with the UI. Since it is possible to attach any object to that event there is no reason to do manual marshalling. The progress is communicated via another async operation - so there is no need to worry about neither how fast the UI can handle the progress events nor if the background thread gets interruped by waiting for the event to finish.
If you prove that the background thread is raising the progress changed event way too fast then you might want to look at Pull vs. Push models for UI updates an excellent article by Ayende.
I just fought a similar situation - badkground thread updating the UI via BeginInvokes. The background has a delay of 10ms on every loop, but down the road I ran into problems where the UI updates which sometimes get fired every time on that loop, can't keep up with teh freq of updates, and the app effectively stops working (not sure what happens- blew a stack?).
I wound up adding a flag in the object passed over the invoke, which was just a ready flag. I'd set this to false before calling the invoke, and then the bg thread would do no more ui updates until this flag is toggled back to true. The UI thread would do it's screen updates etc, and then set this var to true.
This allowed the bg thread to keep crunching, but allowed the ui to shut off the flow until it was ready for more.
Create a new UserControl, add your control and format it (maybe dock = fill) and add a property.
now configure the property to invoke the usercontrol and update your element, each time you change the property form any thread you want!
thats my solution:
private long value;
public long Value
{
get { return this.value; }
set
{
this.value = value;
UpdateTextBox();
}
}
private delegate void Delegate();
private void UpdateTextBox()
{
if (this.InvokeRequired)
{
this.Invoke(new Delegate(UpdateTextBox), new object[] {});
}
else
{
textBox1.Text = this.value.ToString();
}
}
on my form i bind my view
viewTx.DataBindings.Add(new Binding("Value", ptx.CounterTX, "ReturnValue"));
This is a problem that I solved in Update Controls. I bring this up not to suggest you rewrite your code, but to give you some source to look at for ideas.
The technique that I used in WPF was to use Dispatcher.BeginInvoke to notify the foreground thread of a change. You can do the same thing in Winforms with Control.BeginInvoke. Unfortunately, you have to pass a reference to a Form object into your data object.
Once you do, you can pass an Action into BeginInvoke that fires PropertyChanged. For example:
_form.BeginInvoke(new Action(() => NotifyPropertyChanged(propertyName))) );
You will need to lock the properties in your data object to make them thread-safe.
This post is old but I thought I'd give options to others. It seems once you start doing async programming and Windows Forms databinding you end up with problems updating Bindingsource datasource or updating lists bound to windows forms control. I am going to try using Jeffrey Richters AsyncEnumerator class from his powerthreading tools on wintellect.
Reason:
1. His AsyncEnumerator class automatically marshals background threads to UI threads so you can update controls as you would doing Synchronous code.
2. AsyncEnumerator simplifies Async programming. It does this automatically, so you write your code in a Synchronous fashion, but the code is still running in an asynchronous fashion.
Jeffrey Richter has a video on Channel 9 MSDN, that explains AsyncEnumerator.
Wish me luck.
-R
I am late to the party but I believe this is still a valid question.
I would advise you to avoid using data binding at all and use Observable objects instead.
The reason is, data binding looks cool and when implemented the code looks good, but data binding miserably fails when there is lot os asynchronous UI update or multi-threading as in your case.
I have personally experienced this problem with asynchronous and Databinding in prod, we even didn't detect it in testing, when users started using all different scenarios things started to break down.