关于在MvvmCross中何时何地使用ObservableCollection的建议

时间:2013-08-27 12:49:50

标签: mvvm windows-phone-8 xamarin.ios mvvmcross

在MvvmCross解决方案中,我有一个单例服务类,它从Web服务获取项目并更新公共ObservableCollection。它每五秒执行一次,可以添加或删除项目或更改其属性。

我还有一个ViewModel,它有一个公共属性,设置为Service的ObservableCollection。视图绑定到ObservableCollection,以便在添加,删除或更改项目时,视图应更新以显示此内容。

然而,正如预期的那样,我得到了一个线程异常,因为ObservableCollection正在由Main / UI之外的线程更新,因此绑定无法更新UI。

在服务中我没有InvokeOnMainThread调用随时可用,因此在更新ObservableCollection时没有明显的跨平台方法可以返回主线程。此外,这样做似乎是错误的 - 服务不应该关注UI问题(而ViewModel可以)。

我也有点担心从服务中暴露事件,以防这会导致ViewModel不被垃圾收集。我注意到在@ slodge的N + 1系列http://mvvmcross.wordpress.com/中,他正在使用一种消息服务,大概是为了避免这种情况。

因此,一个可能的解决方案可能是发布带有最新项目列表的消息,并且ViewModel可以通过比较消息内容来订阅消息并在UI线程上更新自己的ObservableCollection。但这似乎有点笨拙。

任何有关实施此方法的最佳方式的建议都将受到赞赏 - 谢谢。

1 个答案:

答案 0 :(得分:13)

必须在UI线程上调用INotifyCollectionChanged的原始要求实际上来自Windows控制基于添加/删除/移动/替换/重置通知更新的同步方式。

这种同步更新当然是完全合理的 - 当另一个线程正在积极地更改它时,更新UI显示将非常困难。

.Net 4.5中存在“新”变化,这可能意味着未来更加美好......但总体而言,这看起来相当复杂 - 请参阅https://stackoverflow.com/a/14602121/373321


我知道处理此问题的方法与您帖子中列出的方法基本相同:

一个。保留服务/模型层中的ObservableCollection并将其中的所有事件编组到UI线程上 - 这可以使用任何继承自MvxMainThreadDispatchingObject的类 - 或者可以通过调用MvxMainThreadDispatcher.Instance.RequestMainThreadAction(action) <来完成/ p>

虽然不幸的是,这意味着您的服务/模型确实具有一些线程知识,但这种方法可以很好地适用于整体应用体验。

B中。在ViewModel中制作集合的副本 - 通过一些弱引用类型机制更新它

  • e.g。通过发送消息告诉它添加,删除,替换或移动(或完全重置)的内容 - 请注意,为了使其正常工作,消息以正确的顺序到达非常重要!

  • 或者例如允许从服务/模型层发送快照

选择以下哪项取决于:

  • 集合的频率,类型和大小发生变化 - 例如您是否只是偶尔获得单行更新,是否经常进行大量更改,或者您是否主要看到复杂的更改组(就UI而言基本上是Resets
  • UI中所需的动画级别 - 例如应该添加/删除项目动画进/出?如果不需要动画,那么有时可以更简单地用新快照替换整个列表,而不是计算增量更改。
  • 集合本身的大小 - 显然重复大集合可能会导致内存不足问题
  • 集合所需的持久性 - 如果需要持久性,那么ObservableCollection本身可能不合适,您可能需要使用自定义INotifyCollectionChanged实现(如the MyCustomList samples

我个人通常在应用程序中选择(A)方法 - 但它确实取决于情况以及集合的特征及其变化​​。

请注意,虽然这绝对是一个mvvm问题,但基本问题是一个独立于数据绑定的问题 - 当列表本身在后台线程上更改时,如何更新列表的屏幕显示?