Neha
Neha

Reputation: 184

Accessing UI thread collection from worker thread

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

Answers (2)

AwkwardCoder
AwkwardCoder

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

Flat Eric
Flat Eric

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

Related Questions