WPF How to update GUI when background thread finishes creating collections? - c#

So I want to load my data collections in a background thread and then bind my treeview to the new collection (rather than having the background thread queue things up on the dispatcher every time it wants to add an item to the list [sounds inefficient]).
Is this possible? I create the new data structure and it is output as pd.result on a background thread. When the UI thread checks that the dialog box has closed, it should then set
ModuleHierarchyVM.TopLevelModules = pd.Result as ObservableCollection<ModuleViewModel>;
after this the event OnLoadVCD is called. I have an event handler that then tries to set
a treeview's itemsource to the new collection.
this.AvailableModulesTreeView.ItemsSource = gvvm.ModuleHierarchyVM.TopLevelModules;
This crashes with the error:
"The calling thread cannot access this object because a different thread owns it."
Not even sure how to debug it, the call stack doesn't give any real details.
However, if I just set the Itemsource to a blank new empty collection like so:
this.AvailableModulesTreeView.ItemsSource = (IEnumerable<object>)new List<object>();
it doesn't crash (but then it's not displaying my data either). Any ideas what could be causing the crash?
I thought it might be that I was updating the UI from the wrong thread, so I tried both calling the dispatcher with begininvoke, and checking that I am indeed the UI thread with dispatcher.checkaccess(). so that does not seem to be the issue. However, I really don't know what is going on.
Another way I could implement this is to just make my parsing routine just update the original data structure that is bound to the treeview by caling dispatcher on each item as it is added to the observable collection. However, even if that is the only solution, I really dislike not knowing why something doesn't work. In my mind, it seems reasonable to just create an entirely new data structure on a different thread, and then rebind the new datastructure to the treeview, discarding the old one. It also seems cleaner to me than dozens of 1 line ObservableCollectionInstance.Add calls being placed on the dispatcher while parsing through a file on the background thread.
Full Code:
method called by UI thread
public bool LoadPortInterface(string VCDFileName)
{
ProgressDialog pd = new ProgressDialog("Loading File: ", VCDFileName);
pd.Owner = Application.Current.MainWindow;
pd.WindowStartupLocation = WindowStartupLocation.CenterOwner;
ModuleHierarchyVM.TopLevelModules.Clear();
VCDData TempVCDOutput = null;
Func<object> handler = delegate
{
return VCDParser.ParseVCDFileForAllPorts(VCDFileName, this, pd.Worker, out TempVCDOutput);
};
pd.RunWorkerThread(handler);
pd.ShowDialog();
if (pd.DialogResult == true)
{
ModuleHierarchyVM.TopLevelModules = pd.Result as ObservableCollection<ModuleViewModel>;
VCDOutput = TempVCDOutput;
}
OnLoadVcd();
}
Response to OnLoadVCD event handler in graphviewer:
void gvvm_LoadVCDEvent(object sender, EventArgs e)
{
this.AvailableModulesTreeView.ItemsSource = gvvm.ModuleHierarchyVM.TopLevelModules;
}

I think it will be easer to use TPL "Task Parallel Library"
For example, if you want to create new thread you can create it as task.
var task = Task.Factory.StartNew(() =>
{
// write what you want to do here
}
You can get more examples from this link Task Parallelism (Task Parallel Library)
So, to update the UI from thread, you can run this thread in the same of UI thread as below:
var uiContext = TaskScheduler.FromCurrentSynchronizationContext();
_taskFactoryWrapper.StartTask(() => DoSomeWork(viewSettings.AnyValue)).ContinueWith(task =>
{
viewSettings.Result= task.Result;
},TaskContinuationOptions.AttachedToParent)
.ContinueWith(t => EndingUploadingProgress(viewSettings), uiContext);
So you can create a TaskScheduler associated with the current UI thread.]

You are most likely creating, reading or modifying the ObservableCollection on a thread other than the UI thread. Also make sure you are not adding to or removing from the ObservableCollection on anything other than the UI thread.
To debug this, put a breakpoint wherever you access/modify the observable collection and note the thread number (Thread window in VS) that hits that breakpoint. It should always be the same.
You could use another structure (List/Array) to hold the results, then call back to the UI thread to update/create the ObservableCollection. Updating the ObservableCollection is inexpensive, even for hundreds of items.
What does get expensive is that ObservableCollection will raise a change event on every change, which may be handled by the UI components to change their layout, which has to be done on the UI thread anyway. This UI event handling is why ObservableCollection prevents you from modifying across threads.
If you are adding/removing a large number of items, it may be better to create a new collection and reassign the DataSource. If you always do this, you can use a List instead. ObservableCollection is for when you want to modify the list and have the control only change the smallest amount possible. Changing the DataSource (eg to List) will clear the control and rebuild it, which may be better for many changes.
See:
Updating an ObservableCollection in a separate thread
How do I update an ObservableCollection via a worker thread?
What's the best way to update an ObservableCollection from another thread?

Related

how to use data from one Thread in another [duplicate]

I've got an ObservableCollection<A> a_collection; The collection contains 'n' items. Each item A looks like this:
public class A : INotifyPropertyChanged
{
public ObservableCollection<B> b_subcollection;
Thread m_worker;
}
Basically, it's all wired up to a WPF listview + a details view control which shows the b_subcollection of the selected item in a separate listview (2-way bindings, updates on propertychanged etc.).
The problem showed up for me when I started to implement threading. The entire idea was to have the whole a_collection use it's worker thread to "do work" and then update their respective b_subcollections and have the gui show the results in real time.
When I tried it , I got an exception saying that only the Dispatcher thread can modify an ObservableCollection, and work came to a halt.
Can anyone explain the problem, and how to get around it?
New option for .NET 4.5
Starting from .NET 4.5 there is a built-in mechanism to automatically synchronize access to the collection and dispatch CollectionChanged events to the UI thread. To enable this feature you need to call BindingOperations.EnableCollectionSynchronization from within your UI thread.
EnableCollectionSynchronization does two things:
Remembers the thread from which it is called and causes the data binding pipeline to marshal CollectionChanged events on that thread.
Acquires a lock on the collection until the marshalled event has been handled, so that the event handlers running UI thread will not attempt to read the collection while it's being modified from a background thread.
Very importantly, this does not take care of everything: to ensure thread-safe access to an inherently not thread-safe collection you have to cooperate with the framework by acquiring the same lock from your background threads when the collection is about to be modified.
Therefore the steps required for correct operation are:
1. Decide what kind of locking you will be using
This will determine which overload of EnableCollectionSynchronization must be used. Most of the time a simple lock statement will suffice so this overload is the standard choice, but if you are using some fancy synchronization mechanism there is also support for custom locks.
2. Create the collection and enable synchronization
Depending on the chosen lock mechanism, call the appropriate overload on the UI thread. If using a standard lock statement you need to provide the lock object as an argument. If using custom synchronization you need to provide a CollectionSynchronizationCallback delegate and a context object (which can be null). When invoked, this delegate must acquire your custom lock, invoke the Action passed to it and release the lock before returning.
3. Cooperate by locking the collection before modifying it
You must also lock the collection using the same mechanism when you are about to modify it yourself; do this with lock() on the same lock object passed to EnableCollectionSynchronization in the simple scenario, or with the same custom sync mechanism in the custom scenario.
Technically the problem is not that you are updating the ObservableCollection from a background thread. The problem is that when you do so, the collection raises its CollectionChanged event on the same thread that caused the change - which means controls are being updated from a background thread.
In order to populate a collection from a background thread while controls are bound to it, you'd probably have to create your own collection type from scratch in order to address this. There is a simpler option that may work out for you though.
Post the Add calls onto the UI thread.
public static void AddOnUI<T>(this ICollection<T> collection, T item) {
Action<T> addMethod = collection.Add;
Application.Current.Dispatcher.BeginInvoke( addMethod, item );
}
...
b_subcollection.AddOnUI(new B());
This method will return immediately (before the item is actually added to the collection) then on the UI thread, the item will be added to the collection and everyone should be happy.
The reality, however, is that this solution will likely bog down under heavy load because of all the cross-thread activity. A more efficient solution would batch up a bunch of items and post them to the UI thread periodically so that you're not calling across threads for each item.
The BackgroundWorker class implements a pattern that allows you to report progress via its ReportProgress method during a background operation. The progress is reported on the UI thread via the ProgressChanged event. This may be another option for you.
With .NET 4.0 you can use these one-liners:
.Add
Application.Current.Dispatcher.BeginInvoke(new Action(() => this.MyObservableCollection.Add(myItem)));
.Remove
Application.Current.Dispatcher.BeginInvoke(new Func<bool>(() => this.MyObservableCollection.Remove(myItem)));
Collection synchronization code for posterity. This uses simple lock mechanism to enable collection sync. Notice that you'll have to enable collection sync on the UI thread.
public class MainVm
{
private ObservableCollection<MiniVm> _collectionOfObjects;
private readonly object _collectionOfObjectsSync = new object();
public MainVm()
{
_collectionOfObjects = new ObservableCollection<MiniVm>();
// Collection Sync should be enabled from the UI thread. Rest of the collection access can be done on any thread
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{ BindingOperations.EnableCollectionSynchronization(_collectionOfObjects, _collectionOfObjectsSync); }));
}
/// <summary>
/// A different thread can access the collection through this method
/// </summary>
/// <param name="newMiniVm">The new mini vm to add to observable collection</param>
private void AddMiniVm(MiniVm newMiniVm)
{
lock (_collectionOfObjectsSync)
{
_collectionOfObjects.Insert(0, newMiniVm);
}
}
}
I used a SynchronizationContext:
SynchronizationContext SyncContext { get; set; }
// in the Constructor:
SyncContext = SynchronizationContext.Current;
// in the Background Worker or Event Handler:
SyncContext.Post(o =>
{
ObservableCollection.AddRange(myData);
}, null);
MicrosoftDocs
Platform code for UI (layout, input, raising events, etc.) and your app’s code for UI all are executed on the same UI thread
ObservableCollection is raising CollectionChanged event when one of these actions occurs: Add, Remove, Replace, Move, Reset.. And this event must be raised on UI thread, otherwise, an exception will occur in the caller thread
This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.
And the UI won't updated.
If you want to update the UI from a background thread, Run the code in Application's dispatcher
Application.Current.Dispatcher.Invoke(() => {
// update UI
});
#Jon answer is good but it lacks a code sample:
// UI thread
var myCollection = new ObservableCollection<string>();
var lockObject = new object();
BindingOperations.EnableCollectionSynchronization(myCollection, lockObject );
[..]
// Non UI thread
lock (lockObject)
{
myCollection.Add("Foo")
}
Also note that the CollectionChanged event handler will still be called from the non UI thread.

C# thread safety (in particular MVVM/WPF)

I'm wondering what I need to do to make models thread safe in MVVM. Say I had the following class, which is instantiated as a singleton:
public class RunningTotal: INotifyPropertyChange
{
private int _total;
public int Total
{
get { return _total; }
set
{
_total = value;
PropertyChanged("Total");
}
}
...etc...
}
My view model exposes it via a property:
public RunningTotal RunningTotal { get; }
And my view has a textblock bound to it, i.e. {Binding Path=RunningTotal.Total}.
My app has a background thread that periodically updates the value of Total. Assuming nothing else updates Total, what (if anything) should I do to make all this thread-safe?
Now, what if I wanted to do something similar but using a property of type Dictionary<>, or ObservableCollection<>? Which members (add, remove, clear, indexer) are thread-safe? Should I use a ConcurrentDictionary instead?
My app has a background thread that periodically updates the value of Total. Assuming nothing else updates Total, what (if anything) should I do to make all this thread-safe?
For scalar properties, you don't need to do anything special; the PropertyChanged event is automatically marshaled to the UI thread.
Now, what if I wanted to do something similar but using a property of type Dictionary<>, or ObservableCollection<>? Which members (add, remove, clear, indexer) are thread-safe? Should I use a ConcurrentDictionary instead?
No, this is not thread-safe. If you change the content of an ObservableCollection<T> from a background thread, it will break. You need to do it on the UI thread. An easy way to do it is to use a collection that raises its events on the UI thread, like the one described here.
As for Dictionary<TKey, TValue>, it doesn't raise a notification when its content changes, so the UI is not notified anyway.
Say that there are two threads updating Total, and you want to log all changes to _total in the PropertyChanged method. Now there is a race condition in which PropertyChanged can miss a value. This happens when a thread blocks in the middle of calling set_Total. It updates _total but does yet call PropertyChanged. In the meantime, another thread updates _total to another value:
thread1: _total = 4;
thread2: _total = 5;
thread2: PropertyChanged("Total");
thread1: PropertyChanged("Total");
Now, PropertyChanged is never called with the value of 4.
You can solve this by passing the value to the PropertyChanged method, or by using a lock in the setter.
Since you say that you have one thread which updates this property, there is no possibility for a race condition. This is only the case when multiple threads (or processes) update the same thing at the same time.
The model should be written in a thread-safe way just like any code must be; it's up to you to determine whether you are using locks, concurrent containers or anything other to do it. The models are just library code, which (almost) shouldn't know that its functionality is going to be consumed by a MVVM application.
The VMs, however, have to work in the UI thread. This means that typically they cannot rely that the events from model are coming in the UI thread, so they have to marshal the calls or store them in a task queue if the subscribed events are coming not at the UI thread.
So, the VM is the place which should care about thread safety in a specific way, more than the model needs to.
The View code, in turn, can usually live in happy ignorance about all the threading issues: it gets all the messages/calls/events/whatever in the dedicated UI thread, and makes it own calls in the UI thread as well.
Specifically for your case, your code is not the model but VM, right? In this case you have to fire your events in the UI thread, otherwise the View will be unhappy.
This question provides a thread-marshalled version of the ObservableCollection
How do you correctly update a databound datagridview from a background thread
However, you still need to worry about contention between threads, which would require you to lock resources when they are updated, or use something like Interlocked.Increment.
If one thread is updating, and another is reading, there exists the possiblity that a read is done half way through an update (For example, an Int64 is being modified. The first half (32 bits) has been updated in one thread, and before the second half has been updated, the value is read from a second thread. A completely wrong value is read)
This may or may not be a problem depending on what your application is going to do as a result. If the wrong value will be flashed on the GUI for 1 second, then its probably not a big deal, and the performance penalty of the lock can be ignored. If your program is going to take action based on that value, then you probably need to lock it down.
A simple answer is that you need to schedule the property updates in UI Thread through UI Thread's Dispatcher. This will put updates operation in a queue which will not crash the application.
private void handler(object sender, EventArgs e)
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate { updates(); });
}
private void updates() { /* real updates go here */ }
Some thing more elaborate that it is actually so simple... When instantiating your viewmodel in your view just pass the dispatcher down in the ctor.
ServerOperationViewmodel ViewModel;
public pgeServerOperations()
{
InitializeComponent();
ViewModel = new ServerOperationViewmodel(Dispatcher);
}
Then in your View model:
Dispatcher UIDispatcher;
public ServerOperationViewmodel(Dispatcher uiDisp)
{
UIDispatcher = uiDisp;
}
And use it like a normal UI dispatcher.
UIDispatcher.Invoke(() =>
{
.......
});
I will admit that I am still fairly new to MVVM, but I don not think this breaks the MVVM motto.

How to Update a C# chart control using databinding

I have a C# Chart Control and I data bind it like so.
chart.Series[0].Points.DataBindXY(xAxis, yAxis);
where xAxis is List<String> and yAxis is List<Double>
On another thread xAxis, and yAxis are constantly updated (Multiple calls to .Add())
However the chart does not update unless I call DataBindXY() again, however this seems to cause issue because every once and a while i get
Error: "Collection was modified; enumeration operation may not execute."
Which at some point causes my program to crash with
Error: "system.reflection.targetinvocationexception' occurred in mscorlib.dll"
-Is there something im missing as far as updating? or should I be doing this diffrently, let me know if you need more information.
You need to add locking or synchronization both in your update method and your DataBindXY method. You cannot modify a List and read it at the same time, because operations on Lists are not thread safe.
I'd recommend reading this (or one of the many, many other) introductions on thread synchronization in C#: http://msdn.microsoft.com/en-us/library/ms173179.aspx
EDIT: Here is an example of how to do this:
Object lockOnMe = new Object();
... in your Add loop
(int i = 0; i < dacPoints.Count; i += 1) {
TimeSpan span = new TimeSpan(0, 0, i + 1);
lock (lockOnMe) {
presenter.addPoint(span.ToString(), dacPoints[i]);
}
System.Threading.Thread.Sleep(200);
}
... when calling DataBindXY()
lock (lockOnMe) {
// Note that I copy the lists here.
// This is because calling DataBindXY is not necessarily a serial,
// blocking operation, and you don't want the UI thread touching
// these lists later on after we exit the lock
chart.Series[0].Points.DataBindXY(xAxis.ToList(), yAxis.ToList());
}
The chart control reads the datasource once (when you issue the DataBindXY call) which is the reason why it is not updating when you modify the collection.
The reason you are getting the occasional issue is because your background thread doing the update is changing the collection as the chart is reading from it.
You may be better off having the chart axis as an ObservableCollection created on your UI thread. You can then respond to the CollectionChanged event to instruct the Chart to DataBindXY.
HOWEVER, in order to use this correctly, your background threads will need to invoke the add calls to the collection on the UI thread. If you have a reference to the chartcontrol you can use the control.BeginInvoke call.

Thread safety, lists, binding and WPF

I have a WPF ListView that is bound to a collection (List<T>). It is currently updated from the current thread which works ok.
I want to move the logic for updating the list into a thread and I see some potential issues regarding thread safety and the binding of the list. Can I be assured that the binding will not be updated unless I call NotifyPropertyChanged? Is NotifyPropertyChanged a blocking call or does it just add it to a message queue; in this instance surely there may be a condition where I tell the ListView the collection updated, but by the time the binding updates I may be modifying the collection in the other thread which will throw an exception or crash the program.
What is the best method for implementing thread safety in such a scenario?
INotifyPropertyChanged is not thread safe, and it does block the calling thread.
Best? That's A good question. I dunno. The bottom line is that, at some time or another, calls must be marshalled onto the UI thread. When do you do this?
You could 1) prepare everything, then deliver it to the UI thread where the UI is then updated. Or, you could 2) implement INotifyPropertyChanged and make the firing of that event always happen on the UI thread, or 3) you could do one of a number of different things.
Usually, however, you would want updates to the UI to happen all at once (not one at a time, as you would get when adding single items to an ObservableCollection, for instance). So it might be advisable to make some thread safe base classes that implement INotifyProperty and CollectionChanged and use these.
There is nothing in the framework that will do this for you, unfortunately.
You can make the collection update from Dispatcher.Invoke to avoid those threading problems:
void ThreadProc()
{
window.Dispatcher.Invoke(() => {
//UpdateList
});
}

How do I update an ObservableCollection via a worker thread?

I've got an ObservableCollection<A> a_collection; The collection contains 'n' items. Each item A looks like this:
public class A : INotifyPropertyChanged
{
public ObservableCollection<B> b_subcollection;
Thread m_worker;
}
Basically, it's all wired up to a WPF listview + a details view control which shows the b_subcollection of the selected item in a separate listview (2-way bindings, updates on propertychanged etc.).
The problem showed up for me when I started to implement threading. The entire idea was to have the whole a_collection use it's worker thread to "do work" and then update their respective b_subcollections and have the gui show the results in real time.
When I tried it , I got an exception saying that only the Dispatcher thread can modify an ObservableCollection, and work came to a halt.
Can anyone explain the problem, and how to get around it?
New option for .NET 4.5
Starting from .NET 4.5 there is a built-in mechanism to automatically synchronize access to the collection and dispatch CollectionChanged events to the UI thread. To enable this feature you need to call BindingOperations.EnableCollectionSynchronization from within your UI thread.
EnableCollectionSynchronization does two things:
Remembers the thread from which it is called and causes the data binding pipeline to marshal CollectionChanged events on that thread.
Acquires a lock on the collection until the marshalled event has been handled, so that the event handlers running UI thread will not attempt to read the collection while it's being modified from a background thread.
Very importantly, this does not take care of everything: to ensure thread-safe access to an inherently not thread-safe collection you have to cooperate with the framework by acquiring the same lock from your background threads when the collection is about to be modified.
Therefore the steps required for correct operation are:
1. Decide what kind of locking you will be using
This will determine which overload of EnableCollectionSynchronization must be used. Most of the time a simple lock statement will suffice so this overload is the standard choice, but if you are using some fancy synchronization mechanism there is also support for custom locks.
2. Create the collection and enable synchronization
Depending on the chosen lock mechanism, call the appropriate overload on the UI thread. If using a standard lock statement you need to provide the lock object as an argument. If using custom synchronization you need to provide a CollectionSynchronizationCallback delegate and a context object (which can be null). When invoked, this delegate must acquire your custom lock, invoke the Action passed to it and release the lock before returning.
3. Cooperate by locking the collection before modifying it
You must also lock the collection using the same mechanism when you are about to modify it yourself; do this with lock() on the same lock object passed to EnableCollectionSynchronization in the simple scenario, or with the same custom sync mechanism in the custom scenario.
Technically the problem is not that you are updating the ObservableCollection from a background thread. The problem is that when you do so, the collection raises its CollectionChanged event on the same thread that caused the change - which means controls are being updated from a background thread.
In order to populate a collection from a background thread while controls are bound to it, you'd probably have to create your own collection type from scratch in order to address this. There is a simpler option that may work out for you though.
Post the Add calls onto the UI thread.
public static void AddOnUI<T>(this ICollection<T> collection, T item) {
Action<T> addMethod = collection.Add;
Application.Current.Dispatcher.BeginInvoke( addMethod, item );
}
...
b_subcollection.AddOnUI(new B());
This method will return immediately (before the item is actually added to the collection) then on the UI thread, the item will be added to the collection and everyone should be happy.
The reality, however, is that this solution will likely bog down under heavy load because of all the cross-thread activity. A more efficient solution would batch up a bunch of items and post them to the UI thread periodically so that you're not calling across threads for each item.
The BackgroundWorker class implements a pattern that allows you to report progress via its ReportProgress method during a background operation. The progress is reported on the UI thread via the ProgressChanged event. This may be another option for you.
With .NET 4.0 you can use these one-liners:
.Add
Application.Current.Dispatcher.BeginInvoke(new Action(() => this.MyObservableCollection.Add(myItem)));
.Remove
Application.Current.Dispatcher.BeginInvoke(new Func<bool>(() => this.MyObservableCollection.Remove(myItem)));
Collection synchronization code for posterity. This uses simple lock mechanism to enable collection sync. Notice that you'll have to enable collection sync on the UI thread.
public class MainVm
{
private ObservableCollection<MiniVm> _collectionOfObjects;
private readonly object _collectionOfObjectsSync = new object();
public MainVm()
{
_collectionOfObjects = new ObservableCollection<MiniVm>();
// Collection Sync should be enabled from the UI thread. Rest of the collection access can be done on any thread
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{ BindingOperations.EnableCollectionSynchronization(_collectionOfObjects, _collectionOfObjectsSync); }));
}
/// <summary>
/// A different thread can access the collection through this method
/// </summary>
/// <param name="newMiniVm">The new mini vm to add to observable collection</param>
private void AddMiniVm(MiniVm newMiniVm)
{
lock (_collectionOfObjectsSync)
{
_collectionOfObjects.Insert(0, newMiniVm);
}
}
}
I used a SynchronizationContext:
SynchronizationContext SyncContext { get; set; }
// in the Constructor:
SyncContext = SynchronizationContext.Current;
// in the Background Worker or Event Handler:
SyncContext.Post(o =>
{
ObservableCollection.AddRange(myData);
}, null);
MicrosoftDocs
Platform code for UI (layout, input, raising events, etc.) and your app’s code for UI all are executed on the same UI thread
ObservableCollection is raising CollectionChanged event when one of these actions occurs: Add, Remove, Replace, Move, Reset.. And this event must be raised on UI thread, otherwise, an exception will occur in the caller thread
This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.
And the UI won't updated.
If you want to update the UI from a background thread, Run the code in Application's dispatcher
Application.Current.Dispatcher.Invoke(() => {
// update UI
});
#Jon answer is good but it lacks a code sample:
// UI thread
var myCollection = new ObservableCollection<string>();
var lockObject = new object();
BindingOperations.EnableCollectionSynchronization(myCollection, lockObject );
[..]
// Non UI thread
lock (lockObject)
{
myCollection.Add("Foo")
}
Also note that the CollectionChanged event handler will still be called from the non UI thread.

Categories

Resources