4

我们正在使用 Silverlight 上的 OData,使用 DataServiceCollection 获取数据。

所有获取数据的调用 (LoadAsync() LoadNextPartialSetAsync()) 都是在工作线程上完成的。但是,“LoadCompleted”回调以及反序列化和对象物化是在 UI 线程中完成的。

我们对 DataServiceCollection 所在的 System.Data.Services.Client.DLL 进行了反编译,发现确实所有处理 OData 响应的代码都被分派到了 UI 线程。

有没有办法让反序列化在工作线程上被调用?

谢谢亚龙

4

3 回答 3

3

好...

似乎 OData 集合故意移动处理 UI 线程。我猜这是因为旧对象可能具有 UI 绑定的属性。加载其他数据时,这些属性可能会发生变化。

使用查询本身,我能够在工作线程上获得响应。但是,这样做意味着如果 UI 绑定到任何属性,则必须从 OData 上下文中分离对象(或克隆它们)。否则,当对象在工作线程上实现时,后续查询可能会导致属性更改事件。

于 2011-09-26T15:43:04.487 回答
1

您遇到的问题DataServiceCollection<T>是 源自ObservableCollection<T>. 这反过来又被设计为绑定到 UI 元素。ObservableCollection<T>当对观察它的绑定表达式的成员身份进行更改时,会收到通知。然后,此绑定表达式尝试更新目标 UI 元素。如果通知到达非 UI 线程,则会发生异常。

因此,DataServiceCollection<T>故意将物化转移到 UI 线程,以便当项目出现在集合中时,生成的更改通知不会导致异常。如果这种行为对您来说是不可接受的,那么DataServiceCollection<T>它不适合您。

而是通过DataServiceQuery<T>.BeginExecute. 您传递给的回调BeginExecute将在工作线程上执行(至少在使用 ClientHTTP 时会执行,我尚未确定使用 XmlHttp 时会发生什么)。在这里,您可以枚举结果并将它们放置在您喜欢的任何集合类型中。当您准备好显示结果时,您可以切换到 UI 线程。

于 2011-08-29T19:06:48.827 回答
0

回调将始终在 UI 线程上调用。如果请求使用 XmlHttp 堆栈(如果您从 UI 线程调用它,这是默认值),则网络堆栈调用由 WCF 数据服务在 UI 线程上注册的回调。所以在这种情况下,它是 DataServiceCollection/DataServiceContext 的行为,而是底层网络堆栈的行为。如果您从非 UI 线程调用请求,或者将 Http 堆栈显式设置为 Client,则回调将在非 UI 线程(可能是不同的线程)上返回。在让调用者知道之前,我们仍然将其移回 UI 线程。这样做的原因是一致性,特别是因为您无法与后台线程上的 UI 元素进行交互。

如果您要手动执行查询,例如通过 DataServiceContext.BeginExecute,那么具体化(或大部分)由调用者驱动,因为调用只返回尚未填充的 IEnumerable。如果您随后将执行转移到工作线程并在那里枚举结果,则实现将在该线程上发生。

只是好奇,为什么要移动它?您是否正在处理如此多的数据,以至于导致明显的 UI 滞后?

于 2011-08-29T17:01:45.697 回答