odata on silverlight работает только в потоке пользовательского интерфейса


Мы работаем с OData на Silverlight, используя DataServiceCollection для получения данных.

Все вызовы для извлечения данных (LoadAsync () LoadNextPartialSetAsync ()) выполняются в рабочем потоке. Однако обратный вызов "LoadCompleted", а также десериализация и материализация объектов выполняются потоком пользовательского интерфейса.

Мы декомпилировали систему.Данные.Сервисы.Клиент.DLL, где находится DataServiceCollection, и увидел, что действительно весь код, обрабатывающий ответ OData, отправляется в поток пользовательского интерфейса.

Существует ли какой-либо способ вызвать десериализацию в рабочем потоке вместо этого?

Спасибо Ярон

3 4

3 ответа:

Хорошо...

Похоже, что коллекции OData намеренно перемещают обработку потока пользовательского интерфейса. Я предполагаю, что это сделано, потому что старые объекты могут иметь свойства, к которым привязан пользовательский интерфейс. Эти свойства могут изменяться при загрузке дополнительных данных.

Используя сам запрос, я смог получить ответ в рабочем потоке. Однако это означает, что необходимо отсоединить объекты от контекста OData (или клонировать их), если пользовательский интерфейс привязан к какому-либо свойству. В противном случае последующие запросы могут вызывать события изменения свойств, когда объекты материализуются в рабочем потоке.

Проблема заключается в том, что DataServiceCollection<T> является производным от ObservableCollection<T>. Который, в свою очередь, предназначен для привязки к элементам пользовательского интерфейса. При внесении изменений в членство ObservableCollection<T> выражение привязки, наблюдающее это, уведомляется. Затем это выражение привязки пытается обновить целевой элемент пользовательского интерфейса. Если уведомление поступает в поток, не являющийся пользовательским интерфейсом, то возникает исключение.

Следовательно, DataServiceCollection<T> намеренно переносит материализацию в поток пользовательского интерфейса так, чтобы при появлении элементов в коллекции результирующие уведомления об изменениях не приводят к исключению. Если такое поведение неприемлемо для вас, то DataServiceCollection<T> не для вас.

Вместо этого выполните запрос самостоятельно через DataServiceQuery<T>.BeginExecute. Обратный вызов, который вы передаете в BeginExecute, будет выполняться в рабочем потоке (по крайней мере, когда используется ClientHTTP, я еще не установил, что произойдет, когда используется XmlHttp). Здесь вы можете перечислить результаты и поместить их в любой тип коллекции, который вы предпочитаете. Вы можете переключиться на пользовательский интерфейс поток, когда вы будете готовы к отображению результатов.

Обратный вызов будет вызываться всегда в потоке пользовательского интерфейса. Если запрос использует стек XmlHttp (который используется по умолчанию, если вы вызываете его из потока пользовательского интерфейса), то сетевой стек вызывает обратный вызов, зарегистрированный службой данных WCF в потоке пользовательского интерфейса. Поэтому в данном случае это поведение DataServiceCollection/DataServiceContext, но поведение базового сетевого стека. Если вы вызываете запрос из потока, не являющегося UI, или явно устанавливаете стек Http в качестве клиента, то обратный вызов вернется в поток, не являющийся пользовательским интерфейсом (потенциально другой). Мы все еще перемещаем его обратно в поток пользовательского интерфейса, прежде чем сообщить об этом вызывающему объекту. Причина этого-согласованность, тем более что вы не можете взаимодействовать с элементами пользовательского интерфейса в фоновых потоках.

Если бы вы выполнили запрос вручную, например, через DataServiceContext.BeginExecute, то материализация (или большая ее часть в любом случае) управляется вызывающим, так как вызов возвращает только IEnumerable, который еще не заполнен. Если затем вы перенесете выполнение в рабочий поток и перечислите там результаты, материализация произойдет в этом потоке.

Просто любопытно, почему вы хотите его переместить? Вы обрабатываете так много данных, что это вызывает видимую задержку пользовательского интерфейса?