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.
Related
I'm trying to make my program move itself via a call to SetWindowPos every 10 milliseconds, to follow the cursor. Problem is, when my program's main thread is blocked by a Thread.Sleep(), the window stops moving.
I put the call to SetWindowPos into a secondary System.Thread, but it's still blocked. It appears that SetWindowPos is always handled by the thread that owns the window. So if my main thread is busy, the window can't be moved, even if the request is sent from a different thread.
Is there an alternative way to move a window, even when the thread that owns the window is busy? Thanks!
I don't believe so. All UI operations must be performed on the primary application thread which is known as the UI thread in a GUI app. Whether it is a button click event; mouse move; scroll; paint etc including move window, these operations are queued in the applications message queue (sort of like a FIFO buffer that Windows maintains for all apps) which must be processed by the UI thread.
If say a button click event takes a long time becuase the programmer decided to perform a lengthy database operation in the same thread as the callback, then the UI will freeze until the callback is complete which happens to be the database code.
Similarly if somewhere in your UI thread code you have a Thread.Sleep(), then the UI will also freeze during the same period.
Alternatives
You might want to consider moving lengthy operations to another thread or go the easy contempory and recommended way and use async/await. Doing so allows you to perform the lengthy operation without blocking the UI.
Timers
Also, consider using a Timer instead of Thread.Sleep() or equivalent as an alternative to moving the window 100 times a second. Be sure to use the right timer for GUI apps as .NET defines at least four (4) I believe and not all are suitable by default (if at all) for GUI apps.
The following is one of the remarks on Dispatcher class.
If you create a Dispatcher on a background thread, be sure to shut down the dispatcher before exiting the thread.
What are the consequences if one fails to invoke shut down on a dispatcher created on a background thread?
I have an MFC application which creates a WPF window on a background thread. Consequently, a dispatcher is created. When I close the WPF window first, I get to explicitly invoke shutdown on the dispatcher, but when I close the MFC application, the WPF window closes along.
It seems the dispatcher is being shut down implicitly, or the thread is being aborted. Which is it?
Update:
The following method creates a new thread and opens the wpf window.
public void ShowWindow(SomeObject someObject)
{
System.Threading.Thread thread = new System.Threading.Thread((tuple) =>
{
Tuple<Dispatcher, SomeObject> data = tuple as Tuple<Dispatcher, SomeObject>;
Window window = new WPFWindow(data.Item1, data.Item2);
System.Windows.Threading.Dispatcher.Run();
this.tmp = 0;
});
thread.SetApartmentState(System.Threading.ApartmentState.STA);
thread.IsBackground = true;
thread.Start(new Tuple<Dispatcher, SomeObject>(Dispatcher.CurrentDispatcher, someObject));
}
So, I put a break along the statement "this.tmp = 0;" and it doesn't get hit when I close the MFC application. Is it safe to assume that the Dispatcher is not being shutdown, but the thread is being aborted?
If the thread is aborted, what are the consequences?
Update:
On another project, I ran into a problem where the GC doesn't seem to be doing its job. It turns out, it's related to a Dispatcher started on a background thread that is not being shutdown. The WPF application's memory usage just kept increasing every time a task is ran on background thread. So, be sure to invoke shutdown on Dispatchers created on a background thread whether you created a Dispatcher object explicitly or not.
Not invoking shutdown on Dispatcher created on background thread will cause memory/resource leak. Dispatcher objects hang onto resources. Hence, the GC aren't able to clean them up.
To make sure that a dispatcher is shut down properly, in my case, I have to spawn the background thread from the MFC side of the application then have the main thread wait on it before it completely shuts down. As Hans Passant pointed out, MFC doesn't wait unless it is explicitly told.
If you don't shutdown dispatcher, thread will stuck in message loop and don't exit
In the main thread you can do something like
Dispatcher.FromThread(thread).InvokeShutDown();
However this will cause the 'Dispatcher.Run()' to generate an exception, so you also need to change it to
try
{
System.Windows.Threading.Dispatcher.Run();
}
catch {}
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.
Could any one help me to figure out background thread and UI thread in C#.I have googled it but i coudnt find article illustrate both.
A UI thread creates UI elements and waits and responds to events like mouse clicks and key presses. You can only access the UI elements from the UI thread.
There are two types of threads: background and foreground. A UI thread is an example of a foreground thread.
The difference between background and foreground threads is pretty simple. Background threads don't stop a process from terminating, but foreground threads do. When the last foreground thread stops, then all the background threads are also stopped and the process ends.
This website has a lot of information about threading as well as parallel programming: http://www.albahari.com/threading/
Good luck
There is another key issue to keep in mind. There is a single U.I. thread and you can only call methods on U.I. objects in that thread. In another thread you need to call Control.Invoke() to flip to the U.I. thread if you are doing something like update a status bar.
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.