Dispatcher to Thread relationships in WPF - c#

It is not entirely clear to me how many Dispatchers there are in an application and how they are related to, or referenced from Threads.
As I understand it, a WPF application has 2 threads (one for input, the other for UI) and 1 dispatcher (associated to the UI-Thread). What if I create another thread - let's call it "worker thread" - when I call Dispatcher.CurrentDispatcher on the worker thread, which dispatcher will i get?
Another case:
Assume a console application with 2 threads - the main thread, and an input-thread. On the main thread, I first create the input-thread and then i call Application.Run()
Thread thread = new Thread(new ThreadStart(UserInputThreadFunction));
thread.Start();
Application.Run();
There will be one dispatcher, right? On the input-thread, does Dispatcher.CurrentDispatcher return the dispatcher of the main thread? Or what is the proper way of getting an instance to the main thread's dispatcher?
Could it be, that there are more than one dispatcher in a WPF application? Is there any case, it would make sense to create another dispatcher?

WPF application has 2 threads (one
for input, the other for UI)
This statement is not entirely correct. A WPF application has only one UI thread that handles all the UI interaction and user input. There is also a "hidden" thread responsible for rendering, but normally developers don't deal with it.
Dispatcher / Thread relationship is one to one, i.e. one Dispatcher is always assoticated with one thread and can be used to dispatch execution to that thread. Dispatcher.CurrentDispatcher returns the dispatcher for the current thread, that is, when you call Dispatcher.CurrentDispatcher on a worker thread you get a dispatcher for that working thread.
Dispatchers are created on demand, which means if you access Dispatcher.CurrentDispatcher and there is no dispatcher associated with the current thread, one will be created.
That being said, the number of dispatchers in the application is always less or equal to the number of threads in the application.

WPF application by default has only one Dispatcher. The dispatcher is the only thread that will allow you to interact with UI elements. It abstracts implementations from you, so you only need to worry about being on the UI thread ie the Dispatcher.
If you are trying to directly interact with a visual (eg, set a text on a text box using txtBkx.Text = "new"), from a worker thread, then you will have to switch to a UI thread:
Application.Current.Dispatcher.Invoke(
() => { txtBkx.Text = "new"; });
Alternatively you can use SynchronizationContext.Current (while on a UI thread) and use that to execute delegates on a UI thread from a different thread. As you should note that Dispatcher.CurrentDispatcher may not always be set.
Now you can in fact create different WPF windows in the same application and have an individual dispatcher for each window:
Thread thread = new Thread(() =>
{
Window1 w = new Window1();
w.Show();
w.Closed += (sender2, e2) =>
w.Dispatcher.InvokeShutdown();
System.Windows.Threading.Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
As a side note remember in MVVM, you can update model from a non UI thread and raise property changed events from a non UI thread, as WPF will marshal PropertyChanged events for you. Raising CollectionChanged has to be on a UI thread though.

A dispatcher is always associated with a thread and a thread can have at most one dispatcher running at the same time. A thread does not need to have a dispatcher.
By default there is only one Dispatcher - For the UI. Sometimes it makes sense to have other dispatchers, other time it does not. A dispatching thread needs to block in the Dispatcher.Run() method in order to process invokes to the dispatcher. A thread such as your console input thread will not be availible to process invokes.

Related

UI Thread freezes while it shouldn't be

In a WPF application (C#, .NET 4.0, VS 2013), the following code (called from UI thread) freezes UI thread for 1 second:
new Thread(new ThreadStart(() =>
{
Dispatcher.BeginInvoke(new Action(() =>
{
Thread.Sleep(1000);
}));
})).Start();
The Thread.Sleep() is a placeholder. In actual code it will access some UI element and do some time consuming calculation. That also runs on UI thread!
Shouldn't it be run in another thread other than the UI thread? What have I missed?
Dispatcher.BeginInvoke is designed to push operations (via a delegate) onto the UI thread. You have told it to push a Thread.Sleep(1000) onto the UI thread, so yes: the UI thread will freeze.
From MSDN
For example, a background thread that is spun off from the main UI thread cannot update the contents of a Button that was created on the UI thread. In order for the background thread to access the Content property of the Button, the background thread must delegate the work to the Dispatcher associated with the UI thread. This is accomplished by using either Invoke or BeginInvoke. Invoke is synchronous and BeginInvoke is asynchronous.
If you wanted to do the work in the background... you were already on a background thread (before calling Dispatcher.BeginInvoke).
I suspect what you should be doing here is:
use .Invoke to gather values from the UI into the worker
do the processing on the worker
use .Invoke or .BeginInvoke to update the UI
Dispatcher.BeginInvoke executes operations on the main thread. Use this to execute on your thread:
new Thread(new ThreadStart(() =>
{
{
Thread.Sleep(1000);
};
})).Start();
like Marc already said the Dispatcher.BeginInvoke() pushes all the code int the Action to the UI Thread so the code gets executed there if you want your UI to stay responsive, do the Calculations before you call Dispatcher.Begin Invoke and then set your UI Controls in the BeginInvoke.
new Thread(new ThreadStart(() =>
{
int result = MyHeavyCalculation();
Dispatcher.BeginInvoke(new Action(() =>
{
label1.Text = result.ToString();
}));
})).Start();
Or have a look at async-await to execute methods asynchron and dont bother with UI threadsynchronization yourself. Simple Example

Unable to close new WPF window until all UI threads are returned even if dispatcher priority is set to background

I am new to WPF and making it up as I go along so apologies if I have done anything drastically wrong.
I have a main window that makes a new 'error window' once particular user controls have completed their business. This new error window returns a 'loading placeholder' to UI whilst a background thread is updating another part of the 'error window'.
ErrorsWindow errorWindow = new ErrorsWindow();
errorWindow.LoadingPlaceholder.Text = string.Format(#"Loading...
Please wait {1} minutes and {0} seconds to see potential errors",
ConfigurationManager.AppSettings["ErrorWindowWaitSeconds"],
ConfigurationManager.AppSettings["ErrorWindowWaitMinutes"]);
errorWindow.Show();
this.Dispatcher.BeginInvoke((Action)(() =>
{
errorWindow.SetupWindow();
}), System.Windows.Threading.DispatcherPriority.Background);
So my errorWindow shows up in the UI with the loading placeholder text set correctly. The UI then waits 1 minute 30 seconds for the errorWindow.SetupWindow() method to complete. The issue is that during this wait period I cannot close the window until the errorWindow.SetupWindow() method has completed.
Is there a way to allow the window to close and just abort the background thread?
EDIT: I cannot use a backgroundworker or a task as I need to update the UI elements inside the errorWindow.SetupWindow() method
Thankyou in anticipation
Invoking anything on Dispatcher (if Dispatcher is of UI thread) will run your delegate on UI thread only. Hence, you can't close the window till UI thread is busy somewhere else.
Setting priority DispatcherPriority.Background won't make it run on background thread. It set's the delegate DispatcherPriority to Background. It means that all queued delegates on Dispatcher with priority higher than Background will run first before your delegate gets time to execute.
In case you want to run your operation on background thread, use Task or BackgroundWorker.
As per definition from MSDN:
Executes the specified delegate asynchronously at the specified
priority on the thread the Dispatcher is associated with.
As stated above it runs delegate on associated thread of dispatcher. (which might be in your case is UI thread).
I found the answer to my question on another stackoverflow post here:
How to make some Tasks change my WPF controls
It involves doing the long running task on another thread(using System.Task) then using the dispatcher on the separate thread to affect the UI thread with any UI related changes.

STA call from MTA

I am just starting to deal with STA/MTA issues, so apologies for the simplicity of the question. I couldn't find an answer I could actually understand at the bottom of the ladder here.
I am writing a plugin for another piece of software, and come to a point in a worker thread that I need to create some UI elements. I understand that I cannot do that from inside the worker thread since it is not an STA thread, and that I need to get back to the Main (or just another?) STA thread to create the UI elements. Some clarifications would help greatly.
Do all STA threads have the same 'rights', i.e. if the main thread is STA and creates a Window, adds some UI elements to it. Then spawns off another STA thread, and that second thread likewise creates some UI elements, are they doing it in the same 'space' (poor word choice, but I don't know what else to use) and can access each other's UI elements without causing death and destruction? Or do I need to explicitly jump back to the Main/Original STA thread and ONLY ever create UI elements from THAT (not just ANY) STA thread?
If that is the case (only 1 STA thread is allowed to make UI elements) how do I do that correctly? I have seen many posts that related to this but for some reason I can't quite catch what's going on, and would love a REAL simple answer.
Please no 'Here's a cool slick way of doing...' I just need the simple way of at the point of execution where I need some UI elements jumping back over to the main STA thread if that's what's necessary.
If it is not necessary, then I will just make that worker thread an STA thread and continue on my way, is that fair? Or am I courting disaster?
if the main thread is STA and creates a Window, adds some UI elements to it. Then spawns off another STA thread, and that second thread likewise creates some UI elements, are they doing it in the same 'space' [snip...] and can access each other's UI elements without causing death and destruction?
If Thread A and B are both STA, then they can each create and update their own UI elements, but not eachothers. Any other threads that want to affect the UI have to use one of the BeginInvoke style methods to ask the appropriate thread to do the update.
If it is not necessary, then I will just make that worker thread an STA thread and continue on my way, is that fair? Or am I courting disaster?
You may not be able to make the worker thread an STA thread if it's been set to MTA and initialized. You may have to make a new thread.
How do you do it? It seems like you want to use WPF (System.Windows.*) for your UI - so If the app that you are "plugging into" is also using WPF, you should be able to access it and re use it's UI thread. If not, you can make a new thread, and create a new Application on it and call Run. This should set up a dispatcher for you.
Something like this (pseudo code sort-of copied from some working code I have elsewhere)
Dispatcher dispatcher = null; // we 'get to' the UI thread via the dispatcher
if(Application.Current) { // re use an existing application's UI thread
dispatcher = Application.Current.Dispatcher;
} else {
var threadReadyEvent = new ManualResetEvent(false);
var uiThread = new Thread(() => {
Thread.CurrentThread.SetApartmentState(ApartmentState.STA);
var application = new Application();
application.Startup += (sender, args) => {
dispatcher = application.Dispatcher;
threadReadyEvent.Set();
};
// apps have to have a "main window" - but we don't want one, so make a stub
var stubWindow = new Window {
Width = 1, Height = 1,
ShowInTaskbar = false, AllowsTransparency = true,
Background = Brushes.Transparent, WindowStyle = WindowStyle.None
};
application.Run(stubWindow);
}){ IsBackground = true };
uiThread.Start();
threadReadyEvent.WaitOne();
threadReadyEvent.Dispose();
}
dispatcher.Invoke(() => {
// ask the UI thread to do something and block until it finishes
});
dispatcher.BeginInvoke(() => {
// ask the UI thread to do something asynchronously
});
and so forth
If a thread creates a control. Only this specific thread can interact with it, even if there are other STA threads.
In WinForms you would invoke a method on the control: Control.Invoke.In WPF you have the dispatcher to do it: Dispatcher.Invoke.
WinForms:
form1.Invoke(/* a delegate for your operation */)
WPF:
window1.Dispatcher.Invoke(/* a delegate for your operation */)
What you do is instead of changing an object in a "single apartment" you ask (invoke) the STA thread in control of it to do it (the delegate you invoke) for you. You also have BeginInvoke for doing it asynchronously.

Main Form got hang during long running process in different thread.

I'm using threading in my windows form application.
Code
Thread sqlProcessThread = new Thread(new ThreadStart(doSqlWork));
sqlProcessThread.IsBackground = true;
sqlProcessThread.Start();
When ever this thread is called from my form at that time the form got hang.
How can i solve this problem with out using background worker.
You can use property InvokeRequired to check UI acess from different thread.
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(this.updateUI));
return;
}
More information: MSDN documentation
If you use Invoke() from a background thread, it will wait for the UI to respond before continuing.
It's possible for the UI to respond to the Invoke() call by waiting on something which requires the background thread to do further processing. If that happens, you get deadlock.
If you do not require a return value from the UI call, you can often fix this by using BeginInvoke() instead of Invoke().
Calling BeginInvoke() will return immediately to the background thread that calls it, preventing the deadlock.
This has to be used with care.

C# Threading and Forms: NotSupportedException - Use Control.Invoke?

I am trying to run an application with at least two threads: One form for the user interface and one or more worker threads. They are jointly reading/writing from a static class through a number of other classes.
This is why I am passing an instance of the worker class to the display form. I guess that is why it goes wrong for me:
public class CoCoon
{
private Screen displayForm;
private Worker worker;
public ThreadedApp()
{
worker = new Worker (1024);
displayForm = new Screen(worker);
}
public void Run()
{
//thread 1: display form
Thread screenThread = new Thread(() => Application.Run(displayForm));
//thread 2: background worker
Thread workerThread = new Thread(worker.Run) {IsBackground = true};
screenThread.Start();
Thread.Sleep(1000); //if I don't wait a while, I get an ObjectDisposedException!
workerThread.Start();
}
The threads and objects are initiated just fine, but as soon after the Form_Load method is has been handled, an error is thrown on the Application.Run(displayForm) line above. It is an NotSupportedException, with a remark that I should use Control.Invoke. But I am not sure I understand, because I am not letting threads other than the display form's use the controls on it.
I am new to threading. Can anyone help me on my way? Thanks!
PS: One detail - I am developing this for the Windows Mobile platform.
EDIT After popular request hereby the Stack Trace
at Microsoft.AGL.Common.MISC.HandleAr(PAL_ERROR ar)\r\n at
System.Windows.Forms.Control.get_Visible()\r\n at
System.Windows.Forms.Form._SetVisibleNotify(Boolean fVis)\r\n at
System.Windows.Forms.Control.set_Visible(Boolean value)\r\n at
System.Windows.Forms.Application.Run(Form fm)\r\n at
CoCoonWM6.CoCoon.<Run>b__1()\r\n
I recommend that you only have one UI thread, the main thread. You can use your other threads for background operations, but keep all UI stuff on the main thread.
The UI thread should be the only one calling Application.Run. WinForms has other requirements for the UI thread (such as being STA), and those are satisfied by the main thread. In theory, it may be possible for WinForms to support two UI threads, but it's certainly not easy.
I normally recommend other forms of synchronization when you need to update UI controls from a background thread - TaskScheduler or SynchronizationContext. On the mobile platform, unfortunately, your only option is Control.Invoke.
Check out the stack trace for the exception (and post it). You are almost certainly accessing some Control from the worker thread.
This is how you can modify access to a Control (in this example a Label) after you find where you are accessing controls from non-UI threads:
if (label13.InvokeRequired)
{
ChangeTextDelegate changeText = new ChangeTextDelegate(anyChangeTextMethod);
label13.Invoke(changeText, new object[] { newText });
}
else
{
label13.Text = newText;
}
Looks like you're trying to use GUI elements in the background thread. That would explain why you have to call Sleep (otherwise the form and its controls don't finish loading before you try to use them) as well as the Control.Invoke exception (you can't use GUI elements from a non-UI thread). See the docs for Control.Invoke for how you should use it.
Since you don't have BackgroundWorker and Px in the CF, you're indeed forced to use threads directly - though the ThreadPool would probably be better than instantiating new threads, most of the time.

Categories