Wpf INotifyPropertyChanged、ObservableCollection、线程和MVVM

Wpf INotifyPropertyChanged、ObservableCollection、线程和MVVM,wpf,multithreading,mvvm,observablecollection,inotifypropertychanged,Wpf,Multithreading,Mvvm,Observablecollection,Inotifypropertychanged,好的,从昨天开始,我添加了一个新的复杂性层。我们仍然有一个理论模型类,ViewModel和View。这一次,我的模型有一个Threading.Timer(选择它是为了在“错误”的线程上获取计时器回调) 模型有一个ObservableCollection。计时器回调向集合中添加项 ViewModel只是将集合传递给包含绑定到集合的列表框的视图 这不管用 该模型还公开了在同一个计时器回调中更新的字符串 这也通过viewmodel公开,并绑定到文本框 这确实有效 我在谷歌搜索中看到了一些提示,更新集合

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

模型有一个ObservableCollection。计时器回调向集合中添加项

ViewModel只是将集合传递给包含绑定到集合的列表框的视图

这不管用

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

这也通过viewmodel公开,并绑定到文本框

这确实有效

我在谷歌搜索中看到了一些提示,更新集合并不能使INotifyCollectionChanged按预期工作。我得到了一个完全的内爆,甚至没有异常,只是应用程序立即终止

因此有两个问题:

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

第二,是什么让INotifyPropertyChanged与绑定一起工作?我正在将一个字符串属性绑定到一个名为Text的DependencyProperty,那么是DependencyProperty系统将我的更改封送回UI线程吗?编辑:我可以依赖它吗,也就是说,它这样做是因为他们希望我跨线程与它对话,还是因为它是j我不该依赖的东西都有吗

ListBox是通过ItemsSource=“{Binding obscolection}”绑定的。当应用程序崩溃时。实际上,起初我在创建模型时启动了计时器,这是在设置窗口的DataContext时发生的,因此它实际上会轰炸Visual Studio


感谢WPF控件具有线程关联性,这意味着它们的属性只能从UI线程修改。因此,如果从计时器(而不是dispatcher)更新属性值,则必须将此更新封送到UI线程。这是通过dispatcher执行的:

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

数据绑定框架不确保将更新封送到UI线程,因此,如果从其他线程更新模型,这将导致问题。因此,您需要使用与上述相同的模式。换句话说,如果要向可观察集合添加异议,则必须通过Dispatc执行此添加她。

这个问题在WPF中非常普遍。我认为最好的选择是拥有自己的
ObservableCollection
子类,负责自动将事件通知发送到UI线程


既然轮子已经发明出来了,我只想让你看看这个问题的答案:。

那很酷,但是什么是“正确的”从MVVM的角度处理这个问题的过程?所以我模型上的一个线程正在更新一个集合。我的模型现在应该知道Dispatchers吗?这似乎是错误的。这意味着让我的ViewModel更重,以处理模型和视图之间的正确分离。这有意义吗?没有“正确”的方法。但是,我个人的Reference是创建ViewModel所依赖的简单接口IMarshalledInvoker,它有一个方法来调用其他线程上的某些操作。当我将ViewModel与视图耦合时,我创建了一个IMarshalledInvoker,它在幕后使用Dispatcher。有了这个模式,我仍然可以进行单元测试,仍然可以使用设计器支持ort,也就是说,它是一个很好的MVVM;-)啊,好的,现在一切都好起来了。有趣的是,有一些我从未考虑过的相互关联的不同知识点。首先,我们知道制作线程安全的集合是很棘手的。我已经忘记了这一点,也没有在脑海中联想到。。。本质上,我只添加了一个线程。有趣的是,你忘记了为什么要做事情。所以我认为答案的核心是将多个线程的变化漏斗式地转化为一个线程。所以在视图和视图模型之间只有一个通道??谢谢Colin,当你添加你的评论时,我正在键入我的最后一条评论:)Ricky Gervais的猫叫Colin,那不是你,是吗??)不完全是。事实上,数据绑定框架确实确保,如果收到属性更改的通知,它将在UI线程上设置实际控件的属性(甚至还有DispatcherPriority.DataBinding优先级)。这就是为什么字符串文本绑定适用于OP。问题是数据绑定框架没有用于INotifyCollectionChanged绑定的字符串文本绑定。这就是为什么我们必须将任何修改调用封送到UI线程的ObservableCollection。这是否回答了您的问题?