How Dispatcher differs from the background thread? - wpf

How does the Dispatcher concept in .NET 3.5 and WPF differ from the background thread in .NET 2.0 ?
For example what will be difference between statements below:
delegate.Invoke/BeginInvoke
AND
this.dispatcher.Invoke/BeginInvoke

The dispatcher can be thought of as a Queue that events are sent to; a dispatcher will run on the UI thread and execute events for the UI. In windows, UI controls may only be modified by the thread that created them, so any changes to the UI must be done from the UI thread - thus that is one of the critical reasons why operations that modify window elements must be sent to the UI's dispatcher.
A background thread, in turn, is a different thread than the UI. So anything run on one of these threads will not affect or block the UI.

The concept of BeginInvoke and Invoke can be thought of as follows.
BeginInvoke means: "Do this and return before it completes. I either don't care about the return value or you can call me back at this address at some point in the future."
Invoke means: "Do this and I'll sit here and wait for it to complete."
Now how this relates to dispatchers and background threads is another matter altogether. As Justin says, the Dispatcher processes a queue of things to do every time the UI thread becomes idle. A background thread that calls BeginInvoke on the dispatcher will return immediately even though the dispatcher may not have gotten around to processing. If Invoke had been used instead, the background thread would block until the UI thread completed processing. Note that in Silverlight, there is no Invoke on the Dispatcher and in most cases you probably don't want your background thread blocking while the UI thread is processing work.
Conversely, Delegate.BeginInvoke uses worker threads in the thread pool. When you're on the UI thread (or any thread really) you can call BeginInvoke and Invoke on a delegate. BeginInvoke will use a worker thread to call the delegate using the same semantics I described above. Invoke, however, would not use a different thread. It would simply invoke the delegate synchronously in the context of the calling thread and return when completed.
Be careful when using synchronous execution across threads though as this often results in deadlocks if you're not very careful.

Using the dispatcher to execute a long-running operation still causes it to execute on the UI thread, just at a different priority than the current operation. The problem here is that usually, you want your long-running operation to have as much bandwidth as is feasible. Running under the dispatcher, you're throttled by the UI.
The point of the dispatcher is to give an anchor to a background thread back to the UI so that you can for example provide an update to the UI on the progress of your operation.
If you want to run an operation in the background and defer execution to the UI, use a backgroundworker or the new task library. Use the dispatcher to marshal updates back to the UI.

The operations invoked by both methods will be placed on the event queue to be run on the UI thread. Invoke will occur synchronously and will block until the operation completes, BeginInvoke will occur asyncronously allowing the calling method to continue executing.

Related

Multi-thread UI in WPF

I have two UI threads, one is the main thread and the other is a background thread whose ApartmentState is STA. Each thread creates its own window and the background window has a "Cancel" button on it.
The main thread has a function which is busy and needs quite a long time to finish. I hope once the "Cancel" button is clicked, the main thread should stop the time-consuming function.
Below is the pseudo-code in main thread:
for(...)
{
//Option A: Application.DoEvents();
//Option B: Dispatcher.Invoke to update UI in background thread
if(cancel)
return; //Stop the time-consuming function
else
DoSomething;
}
The strange thing is that the click event on "Cancel" button is NOT captured or handled by the background thread. IMO, each thread has its own message queue, and when I click the "Cancel" button, this message should be queued and processed by the background thread immediately, but according to my test locally, this is not true, the background thread never handles the button click event...
Any thoughts?
BTW, I think there are two ways to overcome the above issue, one is to use Application.DoEvents, and the other is to leverage Dispatcher.Invoke. But I'm still curious why the background thread can NOT handle the message immediately. Thanks in advance.
In general, having two user interface threads is often a bad idea, and completely unnecessary.
You'd typically have a single user interface thread, and just move the actual computational work into a background thread. User interface updates would be marshaled back to the main thread as needed. BackgroundWorker is great for this in many cases.
As for cancellation, this is typically best handled using the frameworks cooperative cancelation model which is built around CancellationTokenSource and CancellationToken. These were designed with use across multiple threads in mind, and automatically handle the proper memory barriers required.

Application Dispatcher and Control Dispatcher

Assume i have control button with name "button1" and function with name "doSomething". Function "doSomething" is called from another thread.
i have two method to call function doSomething from UI thread.
First, from control button dispatcher
this.button1.Dispatcher.BeginInvoke(new Action(() => { doSomething(); }));
and Second, from application dispatcher
this.Dispatcher.BeginInvoke(new Action(() => { doSomething(); }));
The result is same, what is the real different ?
The same dispatcher instance is referenced in all controls owned by the same thread. There is no difference.
All of UI controls (which were created normally), share the same dispatcher instance. That dispatcher is working on UI thread. If you create some control on backgroud thread, it will create new dispatcher on that thread, and this will not be very good.
The best way to avoid most problems with threading and UI controls both in WinForms and WPF is to use System.Threading.SynchronizationContext.Current. The workflow is simple: you get System.Threading.SynchronizationContext.Current while you are on UI thread and save it somewhere (for example in a public static field). Then, whenever you want to run some code on UI thread, you access that persisted SynchronizationContext intance and use its Send or Post methods. It will run you delegates on thread, where SynchronizationContext was achieved (for current case on UI thread). Also it is smart enough, to use the current way of Invoking (message loop for WinForms and dispatcher for WPF) and also if you are already calling from UI thread it will just run your delegate synchronously.
Just keep in mind, that you should get SynchronizationContext only after you create your first control on the current UI thread, because SynchronizationContext will be initialized right after that.
In most of the case, We have single UI thread. So, It doesn't make difference you call
control.Dispatcher(which comes inherited from DispatcherObject parent of the controls).
or
Disptacher.Current.
But there are scenarios, where you will end up having multiple dispatchers.
So, in that situation, Control.Dispatcher will help as It will find out the current dispatcher to respect Thread Affinity. In this Dispatcher.Current won't help.
One scenario, having dedicated thread(with dispatcher) for displaying busy indicator as default UI thread is busy in rendering large list of controls.
However, with SynchronizationContext is another way to avoid such issues. but what if that context or thread is no longer required or it has been set to null by any other developer. So, It is always wise to go for Control.Dispatcher in my opinion.

odata on silverlight runs on UI thread only

We're working with OData on Silverlight, using DataServiceCollection to get the data.
All calls for fetching data (LoadAsync() LoadNextPartialSetAsync()) are done on a worker thread. However, the 'LoadCompleted' callback as well as deserialization and object materialization are done the UI thread.
We decompiled the System.Data.Services.Client.DLL where the DataServiceCollection is, and saw that indeed all code handling the response of the OData is dispatched to the UI thread.
Is there any way to get the deserialization to be called on a worker thread instead?
thanks
Yaron
Well...
It seems the OData collections deliberately moves processing the UI thread. I'm guessing this is done because old objects might have properties the UI is bound to. These properties might change when loading additional data.
Using the query itself, I was able to get the response on a worker thread. However, doing this means one MUST detach the objects from the OData context (or clone them) if UI is bound to any property. Otherwise consequent queries might cause property changed events when objects are materializing on the worker thread.
The problem you have is that the DataServiceCollection<T> is derived from the ObservableCollection<T>. Which in turn is designed to be bound to UI elements. When changes are made to the membership of a ObservableCollection<T> a binding expression observing it is notified. This binding expression then attempt to update the target UI element. If the notification arrives on a non-UI Thread then an exception occurs.
Hence the DataServiceCollection<T> deliberately shifts materialisation to the UI Thread so that as items appear in the collection the resulting change notifications do not result in an exception. If this behaviour is unacceptable to you then DataServiceCollection<T> is not for you.
Instead execute the query yourself via the DataServiceQuery<T>.BeginExecute. The callback you pass to BeginExecute will execute on a worker thread (at least it will when ClientHTTP is being used, I have yet established what will happen when XmlHttp is being used). Here you can enumerate the results and place them in whatever collection type your prefer. You can the switch to the UI thread when you are ready to display the results.
The callback will be called always on a UI thread.
If the request was using the XmlHttp stack (which is the default if you call it from a UI thread) then the networking stack invokes the callback registered by the WCF Data Service on the UI thread. So in this case it's a behavior of the DataServiceCollection/DataServiceContext but a behavior of the underlying network stack.
If you call the request from a non-UI thread or you explicitely set the Http stack to be Client then the callback will come back on a non-UI thread (potentially a different one). We still move it back to the UI thread before letting the caller know. The reason for this is consistency, especially since you can't interact with UI elements on background threads.
If you would execute the query manually, so for example through DataServiceContext.BeginExecute, then the materialization (or most of it anyway) is driven by the caller, since the call returns just IEnumerable which is not yet populated. If you would then transfer execution to a worker thread and enumerate the results there, the materialization will happen on that thread.
Just curious, why do you want to move it? Are you processing so much data, that it causes a visible UI lag?

The calling thread cannot access this object because a different thread owns it

I have a WPF window in the main thread. On button clock of this window i am loading the data. Meanwhile i am using a seperate thread to display a wait screen. But i am not able to set the main window as the parent of the wait screen. It throws following error:
The calling thread cannot access this object because a different thread owns it
You want to look into the Dispatcher.Invoke method.
You could use the BackgroundWorker class to perform your asynchronous operations; it should take care of any thread affinity issues you might be having. It's as simple to use as wiring up a couple of events.
This should get you started.
Alternatively you can use Dispatcher.Invoke to perform the operation on the correct thread:
private void DoStuffOnThread()
{
Dispatcher.Invoke(new Action(DoStuffOnUIThread));
}
private void DoStuffOnUIThread()
{
// ...
}
The problem you are running into is that windows/controls have thread affinity (they are "owned" by a particular thread), and you cannot mix them between threads.
If you want the wait screen's parent to be the main window, you should create the wait screen on the main window's thread. Then, on the other thread, you can tell the wait screen to display by using Invoke.
There is a good article on cross-thread operations in WPF here (search down for Figure 4 Updating the UI):
http://msdn.microsoft.com/en-us/magazine/cc163328.aspx

Thread inconsistencies updating form control from thread

I have scenario where thread updates form's control. I followed http://msdn.microsoft.com/en-us/library/ms171728.aspx to make it work, but I was not successful.
Program creates form control(list view), and a thread to fetch information from internet(stock quotes). Whenever user selects a known symbol from other form control, that would be added in listView, this intern adds to thread to fetch quotes from internet, and a delegate would be added to for that specific symbol, thread iterates through all the watch list symbols to fetch quotes from internet whenever there is change in price, thread calls registered delegate. In that delegate I am accessing listView elements, here I am facing problems thread inconsistent issues.
To solve this problem I followed the above mentioned link,
Approach-1) In the delegate I started background worker. Same problem
Approach-2) Main program creates background worker, this worker loops around a list to update in listView. Delegate adds new updated price to list on which background worker is looping. When background worker is accessing listView again thread inconsistent problems arise.
How to resolve this problem?
When background worker is accessing listView again thread inconsistent problems arise.
Yes. This is because it shouldn't be done. A Background Worker only provides safe access to the UI the RunWorkerCompleted and ProgressChanged events. The DoWork event is still run in the non-UI thread. To access the UI from the non-UI thread, "marshal back" to the UI-thread using Control.Invoke or SynchronizationContext.Send (these should lead to further findings if used as keywords.)
Happy coding.

Resources