c # tpl, проблемы с продолжением с «Вызывающий поток не может получить доступ к объекту, потому что другой поток владеет им» - PullRequest
0 голосов
/ 02 февраля 2012

Я использую Visual Studion 2010 (Net 4.0) Я создаю задачу, которая загружает некоторые значения в ObservableCollection и после этого возвращается в пользовательский интерфейс. Это код:

LoadValues = Task.Factory.StartNew<ObservableCollection<DataGridEntity>>(curDataLoader.LoadValuesTask);
ItemsList = LoadValues.Result;
this.DataContext = ItemsList;

Этот фрагмент кода работает отлично! Но со свойством .Result поток пользовательского интерфейса ждет, пока не вернется задача LoadValues. Поэтому я хочу сделать это так:

LoadValues = Task.Factory.StartNew<ObservableCollection<DataGridEntity>>(curDataLoader.LoadValuesTask);
LoadValues.ContinueWith((FinishLoadDataToDataGrid1) =>
{
   ItemsList = LoadValues.Result;
   this.DataContext = ItemsList;
});

Очень небольшая разница. Я использовал ContinueWith, чтобы предотвратить ожидание потока пользовательского интерфейса. Но если я делаю это таким образом, он говорит мне: «Вызывающий поток не может получить доступ к объекту, потому что другой поток владеет им» по адресу this.DataContext = ItemsList; "

Это проблема времени? У кого-нибудь есть идеи?

Ответы [ 2 ]

4 голосов
/ 02 февраля 2012

Вам необходимо использовать TaskScheduler.FromCurrentSynchronizationContext () для запуска ContinueWith в потоке пользовательского интерфейса.

LoadValues = Task.Factory.StartNew<ObservableCollection<DataGridEntity>>(curDataLoader.LoadValuesTask);
LoadValues.ContinueWith((FinishLoadDataToDataGrid1) =>
{
   ItemsList = LoadValues.Result;
   this.DataContext = ItemsList;
}, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
2 голосов
/ 03 февраля 2012

Поскольку вы работаете в потоке пользовательского интерфейса и когда вы используете ContinueWith , ваш пользовательский интерфейс продолжает выполняться в потоке пользовательского интерфейса, а новая задача выполняется в потоке ThreadPool, а когда новая задача завершается, выполняется функция обратного вызова (которая передается вContinueWith) будет выполняться в потоке ThreadPool.Теперь функция обратного вызова пытается получить доступ к объектам, принадлежащим потоку пользовательского интерфейса, и выдает системную ошибку.

Планируя функцию обратного вызова на TaskScheduler.FromCurrentSynchronizationContext () , вы предписываете системе выполнять эту функцию в потоке пользовательского интерфейса ивсе работает.

Это просто объяснение, так как D.Fihnn уже ответил на ваш вопрос.

...