Reputation: 184
I am writing an application in c# wpf in Visual studio 2012. I am using mvvm. I have an ObservableCollectionCriteriaCollection which belongs to UI thread ,for fetching data from database i am using Task.Factory because data is huge and kept on remote server. when i click on GetData Button following code is executed. my code is like this:
void GetData(object obj)
{
if (CriteriaCollection == null)
CriteriaCollection = new ObservableCollection<Criteria>();
if (SelectedIndex != null && SelectedCriteria != null)
{
bool results = this.CriteriaCollection.Any(report =>
report.CriteriaName.Equals(
this.SelectedCriteria.CriteriaName.ToString()));
if (!results)
{
Task.Factory.StartNew(() =>
{
IsBusy = true;
Criteria newCriteria = new Criteria();
ExecuteGetDataFromDB(null);
///some code which populates values and fills newCriteria
CriteriaCollection.Add(newCriteria);
}).ContinueWith(result =>
{
IsBusy = false;
});
}
}
}
I get an exception at line CriteriaCollection.Add(newCriteria); saying This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.
Can anybody help me with this?
Thank you!
Upvotes: 2
Views: 544
Reputation: 25631
The code you have for creating the Task to do the background work is not quite correct, I believe you want something more like this:
IsBusy = true;
Task<SomeResult>.Factory.StartNew(() =>
{
Criteria newCriteria = new Criteria();
return ExecuteGetDataFromDB(newCriteria);
}, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default)
.ContinueWith(t =>
{
CriteriaCollection.Add(t.Result);
IsBusy = false;
}, TaskScheduler.FromCurrentSynchronizationContext());
What this does is create the Task on a background thread and when it completes 'continues with' on the UI thread and hopefully you won't get the exception any more.
Note you'll have to define the class SomeResult
as the return type from ExecuteGetDataFromDB
method.
Upvotes: 0
Reputation: 8111
GUI related code can only be executed from the GUI thread or with a dispatcher from another thread:
Application.Current.Dispatcher.Invoke(new Action(() =>
{
// your GUI related code here
}));
Upvotes: 2