有关在MvvmCross中何时何地使用ObservableCollection的建议 [英] Advice on where and when to use ObservableCollection in MvvmCross
问题描述
在MvvmCross解决方案中,我有一个单例服务类,该类从Web服务获取项目并更新公共的ObservableCollection.它每五秒钟执行一次,并且可能会添加或删除项或更改其属性.
我还有一个ViewModel,它具有一个设置为服务的ObservableCollection的公共属性.视图绑定到ObservableCollection,以便在添加,删除或更改项目时,视图应更新以显示该视图.
但是,正如预期的那样,我收到一个线程异常,因为ObservableCollection是由Main/UI以外的线程更新的,因此绑定无法更新UI.
在Service内,我没有随时可用的InvokeOnMainThread
调用,因此在更新ObservableCollection时没有明显的跨平台方法可返回到主线程.另外,这样做似乎是错误的-服务不应该将自己与UI事务相关(而ViewModel可以).
另外,对于从服务中公开事件,如果这会导致ViewModels不被垃圾收集,我也感到有些紧张.我注意到,在@slodge的N + 1系列 http://mvvmcross.wordpress.com/中,他正在使用信使服务大概就是为了避免这种情况.
因此,一种可能的解决方案可能是发布一条包含最新项列表的消息,然后让ViewModel订阅该消息,并通过将消息内容与其进行比较来在UI线程上更新其自己的ObservableCollection.但这似乎有些笨拙.
对于实现此最佳方法的任何建议,我们将不胜感激-谢谢.
最初必须在UI线程上调用INotifyCollectionChanged
的原始要求实际上来自Windows控件根据添加/删除/移动"更新的同步方式. /已替换/重置通知.
当然,这种同步更新是完全明智的-当另一个线程正在主动更改UI显示时,很难更新它.
.Net 4.5中有新"更改,这可能意味着未来会更好……但是总体而言,这些对我来说看起来相当复杂-请参见 MyCustomList示例)
我个人通常在应用程序中选择(A)方法-但这确实取决于情况,集合的特征及其更改.
请注意,尽管这绝对是mvvm
问题,但潜在的问题是独立于数据绑定的问题-当列表本身在后台线程上更改时,如何更新列表的屏幕显示?>
In an MvvmCross solution I have a singleton Service class which gets items from a web service and updates a public ObservableCollection. It does this every five seconds and items may be added or removed or their properties changed.
I also have a ViewModel which has a public property which is set to the Service's ObservableCollection. The View is bound to the ObservableCollection so that when items are added, removed or changed the view should update to show this.
However, as expected, I am getting a threading exception because the ObservableCollection is being updated by a thread other than the Main/UI one and the binding therefore cannot update the UI.
Within the Service I do not have the InvokeOnMainThread
call readily available so there is no obvious cross platform way to get back on to the main thread when updating the ObservableCollection. Also, doing this just seems wrong - a Service shouldn't be concerning itself with UI matters (whereas a ViewModel can).
Also I am a bit nervous about exposing events from a Service in case this causes ViewModels to not be Garbage Collected. I note that in @slodge's N+1 series http://mvvmcross.wordpress.com/ he is using a messenging service presumably to avoid just this.
So a possible solution may be to publish a message with the latest list of items, and for the ViewModel to subscribe to the message and update its own ObservableCollection on the UI thread by comparing the message contents to it. But this seems a little clunky.
Any suggestions on the best way to implement this would be appreciated - thanks.
The original requirement that INotifyCollectionChanged
must be called on the UI thread really comes from the synchronous way that the Windows controls update based upon the Added/Removed/Moved/Replaced/Reset notifications.
This synchronous update is, of course, entirely sensible - it would be very hard to update the UI display while another thread is actively changing it.
There are 'new' changes in .Net 4.5 which may mean the future is nicer... but overall these look quite complicated to me - see https://stackoverflow.com/a/14602121/373321
The ways I know of to handle this are essentially the same as those outlined in your post:
A. keep the ObservableCollection
in the Service/Model layer and marshal all events there onto the UI thread - this is possible using any class which inherits from MvxMainThreadDispatchingObject
- or can be done by calling MvxMainThreadDispatcher.Instance.RequestMainThreadAction(action)
Whilst it's unfortunate that this means your Service/Model does have some threading knowledge, this approach can work well for the overall App experience.
B. make a duplicate copy of the collection in the ViewModel
- updating it by some weak reference type mechanism
e.g. by sending it Messages which tell it what has been Added, Removed, Replaced or Moved (or completely Reset) - note that for this to work, then it's important that the Messages arrive in the correct order!
or e.g. allowing snapshots to be sent across from the Service/Model layer
Which of these to choose depends on:
- the frequency, type and size of the collection changes - e.g. whether you are only getting occasional single line updates, whether you are getting frequent large bursts of changes, or whether you are mainly seeing complex groups of changes (which essentially are
Resets
as far as the UI is concerned) - the animation level required in the UI - e.g. should added/deleted items animate in/out? If no animation is required then it can sometimes be easier just to replace the entire list with a new snapshot rather than to work out the incremental changes.
- the size of the collection itself - obviously duplicating a large collection can cause out-of-memory issues
- the persistence required on the collection - if persistence is required, then
ObservableCollection
itself may not be appropriate and you may need to use a customINotifyCollectionChanged
implementation (like the MyCustomList samples)
I personally generally choose the (A) approach in apps - but it does depend on the situation and on the characteristics of the collection and its changes.
Note that while this is most definitely an mvvm
issue, the underlying problem is one independent of databinding - how do you update an on-screen display of a list while the list itself is changing on a background thread?
这篇关于有关在MvvmCross中何时何地使用ObservableCollection的建议的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!