This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread
Since your ObservableCollection is created on UI thread, you can only modify it from UI thread and not from other threads. This is termed as thread affinity.
If you ever need to update objects created on UI thread from different thread, simply put the delegate on UI Dispatcher
and that will do work for you delegating it to UI thread. This will work -
public void Load()
{
matchList = new List<GetMatchDetailsDC>();
matchList = proxy.GetMatch().ToList();
foreach (EfesBet.DataContract.GetMatchDetailsDC match in matchList)
{
App.Current.Dispatcher.Invoke((Action)delegate // <--- HERE
{
_matchObsCollection.Add(match);
});
}
}
CollectionView does not support changes to its source collection from a thread different from the dispatcher thread - caused from dispatcher thread
In my case the problem was that the collection view was refreshed in a task. Then later adding to the collection from the Main UI thread caused an exception.
When constructing the view model the collection was refreshed in a delayed task.
public MainVM()
{
//other code...
Task.Delay(100).ContinueWith(_ => UpdatePreferences());
}
public void UpdatePreferences()
{
//other code..
CollectionViewSource.GetDefaultView(Data.Customers).Refresh();
}
I was able to fix the problem by invoking the dispatcher.
Task.Delay(100).ContinueWith(_ => App.Current.Dispatcher.Invoke(()=> UpdatePreferences()));
Error: This type of CollectionView does not support changes to its SourceCollection
Have you tried wrapping all your code which sets up the filter to a call to the WPF dispatcher?
Generally this has to be done if the collection bound to the view is modified in code of a thread different than the UI thread.
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() => {
HeroesDBAddHeroes();
}));
Updating CollectionView in a different thread
I finally what it was working. It was pretty simple.
public class ConsultInvoiceViewModel : ViewModelBase
{
public Context ctx = new Context();
private ICollectionView _dataGridCollection;
private ObservableCollection<Invoice> invoiceCollection;
public ConsultInvoiceViewModel()
{
invoiceCollection = new ObservableCollection<Invoice>();
DataGridCollection = CollectionViewSource.GetDefaultView(Get());
if (!WPFHelper.IsInDesignMode)
{
var tsk = Task.Factory.StartNew(InitialStart);
tsk.ContinueWith(t => { MessageBox.Show(t.Exception.InnerException.Message); }, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());
}
}
private void InitialStart()
{
try
{
State = StateEnum.Busy;
Get();
}
finally
{
State = StateEnum.Idle;
}
}
private void SearchFilter()
{
Task tsk = Task.Factory.StartNew(()=>
{
try
{
State = StateEnum.Busy;
using (var ctx = new Context())
{
var invs = ctx.Invoices
.Where(s.supplier == 1)
.GroupBy(x => new { x.suppInvNumber, x.foodSupplier })
.ToList()
.Select(i => new Invoice
{
suppInvNumber = i.Key.suppInvNumber,
foodSupplier = i.Key.foodSupplier,
totalPrice = i.Sum(t => t.totalPrice),
});
.
App.Current.Dispatcher.Invoke((Action)delegate
{
invoiceCollection.Clear();
if (invs != null)
foreach (var inv in invs)
{
invoiceCollection.Add(inv);
}
});
}
}
finally
{
State = StateEnum.Idle;
}
});
tsk.ContinueWith(t => { MessageBox.Show(t.Exception.InnerException.Message); }, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());
}
private ObservableCollection<Invoice> Get()
{
using (var ctx = new Context())
{
var invs = ctx.Invoices
foreach (var inv in invs)
{
App.Current.Dispatcher.Invoke((Action)delegate
{
invoiceCollection.Add(inv);
});
}
}
Xamarin Forms Android This type of collectionView does not support changes to its sourceCollection from a thread different from the dispatcher thread
I saw the same problem using VS2017 15.9.9. Even the same code that could be archived a week ago threw the above mentioned error. It seems related to local data in the solution. A "clear" build was not sufficient. However manual deletion of the local obj and bin folders followed by archiving (build is done implicitly) solved the problem for me.
mvvm backgroundworker - CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread
I modified my code as follows and it works the second time through now.
void worker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
ScriptModel _newFileResult = new ScriptModel();
ObservableCollection<ScriptModel> _scriptCollectionTemp = new ObservableCollection<ScriptModel>();
for (int i = 0; i < ScriptCollection.Count; i++ )
{
_newFileResult = CheckOutResults.CheckOutResultFiles(ScriptCollection[i], BatteryLocation, SelectedMachine.Machine);
_scriptCollectionTemp.Add(_newFileResult);
worker.ReportProgress(_scriptCollectionTemp.Count);
}
ScriptCollection = _scriptCollectionTemp;
}
Threading and creating ObservableCollection
The problem isn't actually the ObservableCollection<Something>
at all, it's the <ItemsControl ItemsSource="{Binding Settings.collection}"
.
ObservableCollection
itself doesn't have any problem being accessed across multiple threads (as long as those threads are accessing it one at a time). The same goes for normal (non-DependencyProperty
) properties- they don't inheritly belond to a single thread. The WPF binding system can (for the most part) handle changes to bound properties from other threads (provided you aren't using DependencyProperty
). What can't handle changes from other threads, is ItemsControl
.
Let's step through it, but first I have to make a few assumptions. First, I have to assume that collection
is a actually a property, not a field (or is at least exposed via a property), since you can't bind to a field. Second, I'll have to assume that the INotifyPropertyChanged
interface is involved, probably implemented on the Settings
class.
So stepping through:
- In
Settings.Modify
, you executecollection = new ObservableCollection<Something>();
. This successfully updates the property. The WPF binding system gets notified of this change (through the presumedINotifyPropertyChanged
interface) and handles the thread change for you. SoItemsControl.ItemsSource
gets updated on the UI thread, via the binding, to the new value ofcollection
. ItemsControl
takes this newObservableCollection
and creates aCollectionView
which it uses as the data source for its items.- Back in
Settings.Modify
, you callcollection.Add(...)
. This successfully adds an item to theObservableCollection<Something>
, which triggers itsINotifyCollectionChanged.CollectionChanged
event. - The
CollectionView
which theItemsControl
created, handles theCollectionChanged
event, but still on the other thread, where it was raised. TheCollectionView
, as the exception says, doesn't "support changes to its SourceCollection from a thread different from the Dispatcher thread". So it throws an exception. This exception looks like it's coming fromcollection.Add
, but if you look in the call stack, you'll see it actually comes from many frames deeper.collection.Add
is just the deepest level of your code that is involved.
When working with ObservableCollection
s and multiple threads, I would advise creating the full collection on the background thread (if possible), before passing the full collection back to the UI thread for binding. In your example, you could create a local variable, add your items to that, then set it to your collection
property once all the items are in place. Alternatively, you could pass individual items back to the UI thread to be added, using Dispatcher.Invoke
or a Task<Something>
.
Related Topics
Generic Constraints, Where T:Struct and Where T:Class
Could Not Find a Part of the Path ... Bin\Roslyn\Csc.Exe
How to Run a C# Application at Windows Startup
Does .Net Have a Way to Check If List a Contains All Items in List B
How to Return Multiple Result Sets with SQLcommand
Right Click Context Menu for Datagridview
Stop Tabcontrol from Recreating Its Children
Updating Gui (Wpf) Using a Different Thread
What Characters Are Allowed in C# Class Name
Any Faster Way of Copying Arrays in C#
Linq Aggregate Algorithm Explained
Count the Items from a Ienumerable<T> Without Iterating
Write File from Assembly Resource Stream to Disk
Routing in ASP.NET MVC, Showing Username in Url
What Is More Efficient: Dictionary Trygetvalue or Containskey+Item
Insert Entire Datatable into Database at Once Instead of Row by Row