I have a MDI Child Form which contains a DataGridView that is updated continuously with a Timer. I don't want SQL operations that fire on Timer interval to conflict with other operations and therefore want to use a different thread for this MDI Child Form.
I want to know what to create a thread. I am opening this Form from the MDI Parent Form's Load event. Shall I create a thread at that time and put all the loading code of MDI child there or elsewhere?
You can not do any UI things on another thread. A process only get's one UI thread and all UI code should run on that thread (trying to do UI things on a different thread will result in an exception).
What you should do, is have the timer run on the UI thread and spin off to a background thread from there. As the data returns, be aware that you need to use a Dispatcher to sync your results to the UI thread.
Related
I have a situation where I am showing a Window which acts as a splash screen. This window is created on a separate thread from the main ui thread and as such it is associated with its own Dispatcher (i.e. I end up with 2 Dispatchers the Main Ui dispatcher and the "Splash" Dispatcher).
When I close the splash window the Dispatcher associated with the splash window's thread shuts down (though the thread is still running, which is what I want); however, I would like to be able to show the splash window again at a later time on the same thread. The problem I face is the second time I try and do this the Dispatcher complains that it has been shut down.
Is there a way to force a new Dispatcher to be associated with a thread which previously had a Dispatcher associated with it?
Or is there a way to cause the Dispatcher not to shutdown when the window is closed?
I am aware I could solve this issue by creating a new thread, but I really would prefer not to do this. Ideally I want to have one dedicated thread which is responsible for out of band notifications like the splash and popup "toasters".
NOTE:
I've posted the relevant code at this gist: https://gist.github.com/DamianReeves/76771a031f05a8be042d
To answer your first question:
Is there a way to force a new Dispatcher to be associated with a thread which previously had a Dispatcher associated with it?
"When a Dispatcher is created on a thread, it becomes the only Dispatcher that can be associated with the thread, even if the Dispatcher is shut down."
also
"If a Dispatcher is shut down, it cannot be restarted."
http://msdn.microsoft.com/en-us/library/vstudio/system.windows.threading.dispatcher
in the Remarks section.
Here's a simplified example of what I'm trying to do:
I have 2 controls MyControl c and Panel p. p is created in the main GUI thread as normal, but I want c to be created in a background thread, because it takes awhile and I don't want to freeze the GUI. How can I add c to p.Controls? If I do it in this.Invoke it throws an exception for c, and if I do it from the background thread it throws an exception for p.
Or is it that I really shouldn't be creating GUI elements outside of the main GUI thread?
Or is it that I really shouldn't be creating GUI elements outside of the main GUI thread?
Yes, this is basically the problem. Most controls have thread affinity, and must be created within the user interface thread.
Typically, the way to handle this is to move the "work" that is causing the control creation to be slow onto a background thread, but still create the control on the UI thread. You'd then use Control.Invoke or Control.BeginInvoke to update the information in the UI once the slow work was completed.
For example, if you're loading a set of data from some external source, you can create the control, and start a background thread to load the data. Once the data is loaded, you can then update the control to reflect it. This will cause it to stay responsive the entire time.
It may be that your control does not take a long time to create; rather it takes a long time to get its data. In that case, consider creating a control that can display it UI while it is being populated. Then you can create the control in your main thread, populate it in a background thread, and give your users a better experience.
Use background thread to do what it has to do, and then signal somehow (bool _backgroundCompleted as a trivial example) that c is ready to be created.
Create c from Timer that will fire periodically and do nothing until _backgroundCompleted is set, then create c, then kill the timer.
It might be 'ugly', but it will work and will remain simple.
Forms.Timer, if you are asking ;)
And yeah, NEVER ever mess with multiple threads on the same form. You can have several forms on several threads, but to do that, you have to first RUN a new thread, then create a form ON it. It will have its own message loop, and will do fine.
I am a bit confused about how GUI can be used in multi-threaded applications.
I hear there is a thing called the UI thread. Which I assume is my main executing thread at the startup of the application.
I also hear (though I am not 100% on this) that doing UI stuff on other (non UI) threads is a very bad idea.
So, if I create a separate thread and I want to call MyForm myForm = new MyForm(); myForm.ShowDialog(); in it, what changes do I need to make for that to be "safe"?
Also, I have had some people tell me that events are spun out on a different thread. (Though I am not sure I believe this.) If they are, then I am confused. I can open a dialog (ie myForm.ShowDialog() in an event and nothing truly horrible happens. (Maybe this depends on if the event delegate was called with Invoke or BeginInvoke?)
Here are a few bits of info that may help you out. What you're saying about working with UI on non UI threads isn't just a bad idea, you'll get an exception. Meaning, if you create a Form in the main thread, and then spawn off a background thread to do some processing and then want to update the Form in that background thread, it'll throw an exception. In your example though, where you create the Form in a background thread, you should be OK. I'd question your design, but it won't blow up AS LONG AS YOU ONLY TOUCH THE UI IN THAT SAME THREAD.
As for events, events handlers are executed on the same thread they were raised on. Meaning, if you have a Form on one thread that spawns off some work on another thread that raises events, but before doing so, you hook into this event on the Form thread, you need to be careful not to touch the UI directly in the event handlers, because those event handlers are being called on the background thread.
Finally, the way to correctly manipulate the UI from a background thread, is by calling Invoke and passing in a delegate that does the UI work you want. HTH
In WinForms you need to call UI-things on UI thread, you always can check on what thread you currents are getting InvokeRequired of UI-control.
void ApplyUiChanges()
{
if(this.InvokeRequired)
{
this.Invoke(new Action(ApplyUiChanges));
return;
}
// UI stuff here...
}
In WPF techinic is alike. But instead of using InvokeRequired you should ask CheckAccess() of DispatcherObject (All UI-controls derive from it)
void ApplyUiChanges()
{
if (!dispatcherObject.CheckAccess())
{
dispatcherObject.Dispatcher.Invoke(DispatcherPriority.Send, new Action(ApplyUiChanges));
return;
}
// UI stuff here...
}
Also you can take a look at Async CTP, which might be useful. But it's only CTP, not a release yet.
Another way to handle UI-thread communication is to use PostSharp. Write (or copy-paste) GuiThreadAttribute. After that, you'll be able to use such semantics:
[GuiThread]
void ApplyUiChanges()
{
// UI stuff here...
}
From what I've experienced, "UI thread" is a misnomer. There isn't one single thread that handles all of the UI for an application. To keep things simple, it's generally a good idea to have UI on one thread, but nothing stops you from spawning another thread, and creating new controls on that thread and showing them to the user. What's important is that control properties are only changed on the thread it was created on. As mentioned by another person, you can see if you are currently on that thread by looking at the Control.InvokeRequired property.
If you are on a thread that isn't the one you want a new form to run on and you don't have the luxury of being on the context of a control that is created on the thread you want, then you'll have to get a reference to the System.Threading.SynchronizationContext of the thread you want it to be on (I usually achieve this by storing a reference of System.Threading.SynchronizationContext.Current from the main thread in a static variable, but this can only be done after at least one control has been created on the thread). This object will allow you to run a delegate on its home thread.
I had to do this once in a Windows application that also hosted a WCF service, and UI needed to be launched from the service, but I wanted it on the same thread as the rest of the UI.
HTH,
Brian
In WinForms applications there is only a single thread which is the UI thread. You don't want to block this thread with long operations so that the UI is always responsive. Also you shouldn't update any UI elements from any thread other than the UI thread.
I always use a BackgroundWorker if I want to perform any lengthy operations from the UI. The major benefit of BackgroundWorker is that it can report progress and report that it is complete via ProgressChanged and RunWorkerCompleted. These 2 events occur in the UI thread thus you can update any UI element safely without the need to use InvokeRequired and Invoke.
how can i make a user control to run on its own thread ?
e.g. by following code in a user control , coz user control uses main app thread it make main thread to sleep
Thread.Sleep(TimeSpan.FromMinutes(2));
User controls need to run on the UI thread because that is a restriction in the Windows API. If you try and use Windows Forms controls from another thread you will get an exception.
You can run other code in another thread, but use the UI thread to update the controls. You can use BackgroundWorker for this. Or you can use the InvokeRequired and Invoke or BeginInvoke methods on the control instance to have it execute code on the UI thread.
You mention you want to use a mutex lock. A mutex is to avoid having multiple threads access a resource at the same time. If all your code is running in the same thread then you don't need a lock at all.
Objects don't really "run" themselves - methods are executed on a thread.
Now if you want a particular method to execute in a different thread, you need to either create a new thread, use the threadpool explicitly, or use something which uses the threadpool for you - such as BackgroundWorker.
What are you doing when you want to sleep for two minutes? Could you avoid sleeping by just setting a timer to fire (in the UI thread) in two minutes instead? If this is part of some long-running process, you should use BackgroundWorker or some other way of executing on a different thread, but with the control itself still handling updates and events on the UI thread.
I have thread that monitor the status of the device( using i/o ). This will fire the event to several UI (Forms/Dialogs..) parts about the connection status(Connected, Disconnected, Fault). Based on this status, the forms and dialogs are destroyed, created , enabled and disabled.
My Problem :
I getting Cross-Thread exception because the thread doing the operations like Dispose the from, create the from .... . I using smart client, forms and dialogs are part of the WorkItemController and i just terminating that.
I don't want u use Invoke or BeginInvoke . I want this thread to continue only monitoring the status. SO that this thread has to give its control to the main thread and the main thread will close the form or create the form.
Just i want how to shift the control from one thread to another. Is any way is there?
The best solution is to use Invoke to switch back to your mainthread.
or if you can use global variables shared between the main thread and your background thread, but this means your main thread should check the variables in a loop and this may hang GUI.
Or use System.Windows.Forms.Timer as it executes in the main thread.