When is a dispatcher needed in WPF [duplicate] - wpf

This question already has answers here:
How to update only a property in an observable collection from thread other than dispatcher thread in WPF MVVM?
(3 answers)
Closed 1 year ago.
The suggested duplicate thread did not address my question
So it is my understanding that a WPF application handles everything UI related, button presses, updates to observable collections through the dispatcher thread, which can be called with Application.Current.Dispatcher.Invoke(Update UI element here), while changes to models and data can be handled by background threads normally.
What I don't understand is why you need to call the dispatcher for say updating an observable collection Bound to a Combobox, but yet when I want to update the progress bar or text in a textbox or if a button is enabled I don't need to call the dispatcher. Everything I read states that the dispatcher is used for handling and updating the UI. Are textboxes, the status of progress bars, and whether or not a button is enabled not see as UI?
What is the difference between an Observable collection and text/progress bars that makes calling the dispatcher not required?

Almost any call to a WPF UI element should happen on the main thread of the application.
This is usually done through the methods of the Dispatcher associated with this thread.
The dispatcher can be obtained from any UI element, but usually it is obtained from the application: Applicatiion.Current.Dispatcher.
If you do not assign values ​​directly to the properties of UI elements, but use bindings for this, then the bindings mechanism has built-in marshaling of value assignment into the flow of the UI element.
Therefore, the INotifyPropertyChanged.PropertyChanged event can be raised on any thread.
When the observable collection changes, the INotifyCollectionChanged.CollectionChanged event is raised.
It is not provided for automatic marshaling to the UI thread.
But the collection can be synchronized with the BindingOperations.EnableCollection (...) method.
Then it can be changed (using synchronization) in any thread.
If such synchronization has not been performed, then it can be changed only in the UI thread.
In addition to these events, there is also ICommand.CanExecuteChanged.
There are no additional marshaling or synchronization methods provided for it.
Therefore, it can be raised only in the UI thread.
This is usually built into the WPF implementation of ICommand and the programmer doesn't need to worry about it.
But in simple (mostly educational) implementations, there is no such marshaling.
Therefore, when using them, the programmer himself must take care of the transition to the UI thread to raise this event.
So basically in MVVM practice you no matter what you would have to use a dispatcher to use BindingOperations.EnableCollectionSynchronization(fooCollection, _mylock)); correct?
Yes.
For the application of the collection, you understood correctly.
Here only the problem of separation of the View and ViewModel functionality arises.
You can only call "EnableCollectionSynchronization" on the View or on the main UI thread.
But you are implementing the collection in the ViewModel.
Also, in order not to clog up memory, when deleting a collection (replacing it with another, clearing the bindings that use it, replacing the ViewModel instance, etc.), you need to delete the created synchronization using the "DisableCollectionSynchronization (collection)" method.
In this regard, if a single instance of the ViewModel is used throughout the application session, then using "EnableCollectionSynchronization ()" is the simplest solution.
Example:
public class MainViewModel
{
public ObservableCollection<int> Numbers { get; }
= new ObservableCollection<int>();
protected static readonly Dispatcher Dispatcher = Application.Current.Dispatcher;
public MainViewModel()
{
if (Dispatcher.CheckAccess())
{
BindingOperations.EnableCollectionSynchronization(Numbers, ((ICollection)Numbers).SyncRoot);
}
else
{
Dispatcher.Invoke(()=>BindingOperations.EnableCollectionSynchronization(Numbers, ((ICollection)Numbers).SyncRoot));
}
}
}
But if many VM instances are used, with mutual nesting and dynamic addition and removal (for example, this can be the case when implementing a tree and viewing it in a TreeView), then using "EnableCollectionSynchronization ()" becomes not trivial.
If you do as I showed in the example above, then due to the fact that the reference to the synchronization object, to the collection, will be saved, they will not be deleted from memory and, accordingly, unnecessary instances of ViewModel will not be deleted.
And this will lead to a memory leak.
Therefore, in practice, marshaling of collection changes to the UI thread is often used.
It is also possible to embed in the INotifyCollectionChanged implementation, as well as marshaling to the UI thread, and calling "EnableCollectionSynchronization () / DisableCollectionSynchronization ()" while subscribing / unsubscribing to the CollectionChanged event.
The implementation of the ObservableCollection does not have this, but there are custom implementations of the observable collections in various packages where the similar is implemented.
And their use frees the programmer from creating routine, specific, repetitive code.
Unfortunately, I cannot tell you exactly what the package contains the required implementation.
I prefer to use my own implementations.

Related

Is WPF binding to concurrent collections safe?

I was wondering, if it is safe to bind a WPF control to a concurrent collection, specifically a wrapper class around one of the System.Collections.Concurrent collections that also implements INotifyCollectionChanged?
I understand that CollectionChanged must be invoked on the UI-thread (and without the index parameters). But, what happens, if another thread manipulates the source collection while the UI is updating itself? Does WPF just gracefully ignore the problem (like it does in so many other places)?
That depends on the implementation of your wrapper. Let's make a simple example adding INotifyCollectionChanged to a BlockingCollection<T> allowing calls of non UI threads:
public void AddNotified(T item)
{
base.Add(item);
var args = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Add,
item,
Count - 1);
//Ensure no items are changed until the UI is updated
Application.Current.Dispatcher.Invoke(() =>
CollectionChanged?.Invoke(this, args));
}
The implementation of Add itself is threadsafe, but to be sure the UI shows the current items the implementation you need to ensure that there are no other items are changed between adding and updating (See comment in code).
WPF updates the UI based on the NotifyCollectionChangedAction and updated items passed at raising the INotifyCollectionChanged.CollectionChanged. This means the UI relys on this information. The result: An interim collection update leads to an unsynchronized UI until the update was raised or a NotifyCollectionChangedAction.Reset was called and the UI shows different items like inside your source collection.
Synchronizing collections with the UI is a very wide and intresting topic. There are already multiple solutions available that may match your specific problem. To give you some possible approaches to solve problems like this have a look at here are some links:
Is there a Threadsafe Observable collection in .NET 4?
Threadsafe ObservableCollection
BindingOperations.EnableCollectionSynchronization

How to deal with cross-thread access exceptions?

A common exception one can get when working with multiple threads in WPF is:
The calling thread cannot access this object because a different thread owns it
What are the options to deal with this properly?
Depending on the situation there are various options:
Accessing a control from another thread
e.g. updating a TextBlock with progress information.
Data Binding:
In this case the easiest thing you can do is avoiding the direct interaction with the control. You can just bind the property you want to access or modify to an object whose class implements INotifyPropertyChanged and then set the property on that object instead. The framework will handle the rest for you. (In general you rarely should need to interact with UI-elements directly, you can almost always bind the respective properties and work with the binding source instead; one case where direct control access may be necessary is control authoring.)
There are some cases where data binding alone is not enough, for example when trying to modify a bound ObservableCollection<T>, for this you need...
Dispatching:
You can dispatch your accessing code to the thread owning the object, this can be done by calling Invoke or BeginInvoke on the Dispatcher owning the object being accessed (getting this Dispatcher is possible on another thread).
e.g.
new Thread(ThisThreadStart).Start();
void ThisThreadStart()
{
textBlock.Dispatcher.Invoke(new Action(() => textBlock.Text = "Test"));
}
If it is not clear on which thread a method is executed you can use Dispatcher.CheckAccess to either dispatch or execute an action directly.
e.g.
void Update()
{
Action action = () => myTextBlock.Text = "Test";
var dispatcher = myTextBlock.Dispatcher;
if (dispatcher.CheckAccess())
action();
else
dispatcher.Invoke(action);
}
If an object is not a DispatcherObject and you still need the associated Dispatcher you can use Dispatcher.CurrentDispatcher in the thread creating the object (so doing this in the method being executed by a thread will not do you any good). For convenience as you usually create objects on the application's main UI thread; you can get that thread's Dispatcher from anywhere using Application.Current.Dispatcher.
Special cases:
BackgroundWorker
Move any control access to ProgressChanged as it occurs on the thread that created the instance (which should of course be the UI-thread)
Timers
In WPF you can use the DispatcherTimer for convenience, it does the dispatching for you so any code in Tick is invoked on the associated dispatcher. If you can delegate the dispatching to the data binding system you of course can use a normal timer as well.
You can read more about how the Dispatcher queue works and WPF threading in general on MSDN.
Accessing an object created on another thread
e.g. loading an image in the background.
If the object in question is not Freezable you should in general simply avoid creating it on another thread or restricting access to the creating thread. If it is Freezable you just need to call Freeze to make it accessible to other threads.
Accessing a data object from another thread
That is, the type whose instance is being updated is user-code. If an exception is thrown this situation probably came about by someone using DependencyObject as base type for a data class.
This situation is the same as accessing a control and the same approaches can be applied but usually it should be avoided in the first place. Granted, this allows for simple property change notifications via dependency properties and those properties can also be bound but often enough this is just not worth giving up thread-independency. You can get change notifications from INotifyPropertyChanged and the binding system in WPF is inherently asymmetrical, there always is a property that is bound (target) and something that is the source for this binding. Usually the UI is the target and the data is the source, meaning that only UI components should need dependency properties.
That would be several hundred lines of code, for something I "figured out".
But the summary is:
App_OnStartup
generate a background thread
in the callback,
Call
Application.Current.MainWindow.Dispatcher.CheckAccess() - gets the exception
Application.Current.Dispatcher.CheckAccess() does not
I have a udp listener object that communicates through events where the method/callbacks are +='ed in my mainWindow wpf .cs file.
The event handler functions are called with parameters, one being the message I want displayed in a listbox in the mainWindow.cs
Using the information in this thread by H.B. above;
I have added, tested and handled the crossthread in wpf in my eventhandler callback using the following code, but I use a real message not a hard coded one:
listBox1.Dispatcher.Invoke(new Action(() => listBox1.Items.Add("MessageHere")));
UPDATE:
This is better because you can put more things in the anonymous function.
listBox1.Dispatcher.Invoke((Action)delegate
{
listBox1.Items.Add(e.ReaderMessage);
});

WPF DataBinding Thread Safety

I have a TextBox that's bound to a property that gets modified at a very rapid rate in a background thread. Is data binding in WPF thread safe? Will the data in the property or the TextBox ever get out of sync? Is it necessary (or even possible) to use synchronization on a property that takes part in data binding?
I understand that, if the class on which the property resides implements INotifyPropertyChanged, the binding framework automatically marshalls the UI update to the UI thread. However, doesn't that still allow the data to get out of sync? If I understand correctly, variables that are written from one thread and read from another should by synchronized... is data binding an exception?
thanks!!
Yes, for the most part. Binding is thread safe for single objects (so should be fine for your string). However, binding to a collection is not thread safe - and still requires manually marshaling. If you have a control bound to a collection, you cannot change the collection on a background thread.
I understand that, if the class on which the property resides implements INotifyPropertyChanged, the binding framework automatically marshalls the UI update to the UI thread. However, doesn't that still allow the data to get out of sync?
This shouldn't get out of sync, unless multiple threads are writing to the variable very quickly (in which case, they'll all block until they get back in sync, but there is a period of time where threads will "wait" on the UI). The marshaling happens synchronously, so the thread doesn't receive values until the binding is up to date. This can slow down your processing, as the UI update has to happen before your background thread can continue.
Yes, it is usually thread safe. In WPF (unlike WinForms) the data binding classes look for the UI thread's Dispatcher and use it (if needed) to automatically marshal to the UI thread. Note, however, that this is done synchronously- your background thread will block while the UI is redrawn, and I have seen that cause choppyness, "freezing", and other unintended effects with rapid background updates.
See a similar question here: WPF Databinding thread safety?

INotifyPropertyChanged, ObservableCollection, Threads and MVVM

Ok, following on from yesterday I've added a new layer of complexity. We still have a theoretical Model class, ViewModel and View. This time my Model has a Threading.Timer (Chosen specifically to get timer callbacks on the "wrong" thread.
The Model has an ObservableCollection. The Timer callback adds items to the collection.
The ViewModel simply passes the collection to the View which contains a listbox bound to the collection.
This doesn't work.
The model also exposes a string which is updated in the same timer callback.
This too is exposed via the viewmodel and bound to a TextBox.
This does work.
I've seen hints in my googling that updating collections doesn't make INotifyCollectionChanged work as expected. I get a total implosion, not even an exception, just immediate termination of the application.
So there are two questions:
One relates to our discussion yesterday. I'm using INotifyPropertyChanged and ObservableCollections in my Model because they are the thing upon which the view does work. It still makes sense to me to use these mechanisms to notify my viewmodel, or what ever that the underlying model has changed. So how do I deal with updates occuring on a different thread?
Second, what is happening that makes INotifyPropertyChanged work with the binding? I'm binding a string property to a DependencyProperty called Text, so is it the DependencyProperty system that marshals my change back to the UI thread? Edit: And can I rely on it, i.e. does it do this because they expect me to talk to it cross-thread, or is it just a catch all that I shouldn't rely on?
The ListBox is bound through ItemsSource="{Binding ObsCollection}". When this crashes the application. Actually, at first I started the timer when the Model was created which happened when the Window's DataContext was set, so it would actually bomb Visual Studio...
Thanks
WPF controls have thread-affinity, what this means is that their properties can only be modified from the UI thread. Therefore, if you update a property value from a Timer (other than a DispatcherTimer), you will have to marshal this update onto the UI thread. This is perfomed via the dispatcher:
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Normal,
new Action(() => // update your control here));
The databinding framework does not ensure that updates are marshalled onto the UI thread, therefore, if you update your model from a different thread, this will cause issues. therefore you need to use the same pattern as above. In other words, if you are adding objections to your observable collection, this add must be performed via the Dispatcher.
This problem is quite prevalent in WPF. I think the best option is to have your own ObservableCollection<> subclass that takes care of dispatching event notifications to the UI thread automatically.
And since the wheel has already been invented, I 'm going to simply refer you to the answer to this question: ObservableCollection and threading.

WPF Databinding thread safety?

Well lets say i have an object that i databind to, it implements INotifyPropertyChanged to tell the GUI when a value has changed...
if i trigger this from a different thread than the GUI thread how would wpf behave?
and will it make sure that it gets the value of the property from memory and not the cpu cache?
more or less im asking if wpf does lock() on the object containing the property...
Value changes fired by INotifyPropertyChanged are automatically marshalled back onto the dispatcher. (http://blog.lab49.com/archives/1166)
Fire this event on any thread you like...
Value changes fired by INotifyCollectionChanged are NOT reliably marshalled onto the dispatcher. (http://csharplive.wordpress.com/2008/09/11/wpf-data-binding-observablecollection-cross-thread-binding-support/)
If you need to update an observable collection from a different thread, follow the advice in this link
In addition to #Rob Fonseca-Ensor's answer, there is some good news for those lucky enough to use WPF4.5:
WPF enables you to access and modify data collections on threads other than the one that created the collection. This enables you to use a background thread to receive data from an external source, such as a database, and display the data on the UI thread. By using another thread to modify the collection, your user interface remains responsive to user interaction. (https://msdn.microsoft.com/en-us/library/bb613588(v=vs.110).aspx#xthread_access)
There's a helpful summary by Jonathan Antoine: http://www.jonathanantoine.com/2011/09/24/wpf-4-5-part-7-accessing-collections-on-non-ui-threads/
In practice it seems to work as expected and seems to be thread-safe (haven't seen anything odd happen or exceptions as a result of updating on background thread). I believe it invokes on to the UI thread when needed, but I'm not too familiar with the internals.

Resources