INotifyPropertyChanged、ObservableCollection、线程和 MVVM

发布于 2024-10-10 14:29:28 字数 860 浏览 0 评论 0原文

好的,从昨天开始我添加了一个新的复杂层。我们仍然有一个理论模型类,ViewModel 和 View。这次我的模型有一个 Threading.Timer (专门选择在“错误”线程上获取计时器回调。

模型有一个 ObservableCollection。计时器回调将项目添加到集合中。ViewModel

只是将集合传递到包含列表框绑定到集合。

模型还公开了一个在同一计时器回调中更新的字符串,

也通过视图模型公开并绑定到文本框

这 我在谷歌上搜索到更新集合并没有使 INotifyCollectionChanged 按预期工作,我完全崩溃了,甚至没有异常,只是立即终止了应用程序

一个与我们昨天使用 INotifyPropertyChanged 的​​讨论有关。和 ObservableCollections 在我的模型中,因为它们是视图工作的基础,使用这些机制来通知我的视图模型或底层模型发生的任何变化对我来说仍然有意义。那么我该如何处理不同线程上发生的更新呢?

其次,发生了什么使 INotifyPropertyChanged 与绑定一起工作?我将一个字符串属性绑定到一个名为 Text 的 DependencyProperty,那么 DependencyProperty 系统是否会将我的更改封送回 UI 线程?编辑:我可以依赖它吗,即它这样做是因为他们希望我与它进行跨线程对话,还是它只是我不应该依赖的所有内容?

ListBox 通过 ItemsSource="{Binding ObsCollection}" 进行绑定。当这使应用程序崩溃时。实际上,一开始我在创建模型时启动了计时器,这是在设置窗口的 DataContext 时发生的,所以它实际上会轰炸 Visual Studio...

谢谢

Ok, following on from yesterday I've added a new layer of complexity. We still have a theoretical Model class, ViewModel and View. This time my Model has a Threading.Timer (Chosen specifically to get timer callbacks on the "wrong" thread.

The Model has an ObservableCollection. The Timer callback adds items to the collection.

The ViewModel simply passes the collection to the View which contains a listbox bound to the collection.

This doesn't work.

The model also exposes a string which is updated in the same timer callback.

This too is exposed via the viewmodel and bound to a TextBox.

This does work.

I've seen hints in my googling that updating collections doesn't make INotifyCollectionChanged work as expected. I get a total implosion, not even an exception, just immediate termination of the application.

So there are two questions:

One relates to our discussion yesterday. I'm using INotifyPropertyChanged and ObservableCollections in my Model because they are the thing upon which the view does work. It still makes sense to me to use these mechanisms to notify my viewmodel, or what ever that the underlying model has changed. So how do I deal with updates occuring on a different thread?

Second, what is happening that makes INotifyPropertyChanged work with the binding? I'm binding a string property to a DependencyProperty called Text, so is it the DependencyProperty system that marshals my change back to the UI thread? Edit: And can I rely on it, i.e. does it do this because they expect me to talk to it cross-thread, or is it just a catch all that I shouldn't rely on?

The ListBox is bound through ItemsSource="{Binding ObsCollection}". When this crashes the application. Actually, at first I started the timer when the Model was created which happened when the Window's DataContext was set, so it would actually bomb Visual Studio...

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

荆棘i 2024-10-17 14:29:28

WPF 控件具有线程亲和性,这意味着它们的属性只能从 UI 线程修改。因此,如果您从 Timer(DispatcherTimer 除外)更新属性值,则必须将此更新封送到 UI 线程上。这是通过调度程序执行的:

Application.Current.Dispatcher.BeginInvoke(
  DispatcherPriority.Normal,
  new Action(() => // update your control here));

数据绑定框架不确保将更新编组到 UI 线程上,因此,如果您从不同的线程更新模型,这将导致问题。因此您需要使用与上面相同的模式。换句话说,如果您要向可观察集合添加对象,则必须通过调度程序执行此添加。

WPF controls have thread-affinity, what this means is that their properties can only be modified from the UI thread. Therefore, if you update a property value from a Timer (other than a DispatcherTimer), you will have to marshal this update onto the UI thread. This is perfomed via the dispatcher:

Application.Current.Dispatcher.BeginInvoke(
  DispatcherPriority.Normal,
  new Action(() => // update your control here));

The databinding framework does not ensure that updates are marshalled onto the UI thread, therefore, if you update your model from a different thread, this will cause issues. therefore you need to use the same pattern as above. In other words, if you are adding objections to your observable collection, this add must be performed via the Dispatcher.

友谊不毕业 2024-10-17 14:29:28

这个问题在WPF中相当普遍。我认为最好的选择是拥有自己的 ObservableCollection 子类,负责自动向 UI 线程分派事件通知。

由于轮子已经被发明了,我将简单地向您推荐这个问题的答案:ObservableCollection 和线程

This problem is quite prevalent in WPF. I think the best option is to have your own ObservableCollection<> subclass that takes care of dispatching event notifications to the UI thread automatically.

And since the wheel has already been invented, I 'm going to simply refer you to the answer to this question: ObservableCollection and threading.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文