【问题标题】:INotifyPropertyChanged, ObservableCollection, Threads and MVVMINotifyPropertyChanged、ObservableCollection、线程和 MVVM
【发布时间】:2011-06-03 23:37:47
【问题描述】:

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

模型有一个 ObservableCollection。 Timer 回调将项目添加到集合中。

ViewModel 只是将集合传递给 View,其中包含绑定到集合的列表框。

这不起作用。

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

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

这确实有效。

我在谷歌搜索中看到了更新集合不会使 INotifyCollectionChanged 按预期工作的提示。我完全崩溃了,甚至没有例外,只是立即终止了应用程序。

所以有两个问题:

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

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

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

谢谢

【问题讨论】:

标签: wpf multithreading mvvm observablecollection inotifypropertychanged


【解决方案1】:

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

由于轮子已经被发明出来,我将简单地向您推荐这个问题的答案:ObservableCollection and threading

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

    • 这很酷,但是从 MVVM 的角度来看,处理这个问题的“正确”过程是什么?所以我的模型上的一个线程正在更新一个集合。我的模型现在应该知道调度程序吗?这似乎是错误的。这表明让我的 ViewModel 更重,以应对模型和视图之间的正确分离。这有意义吗?
    • 没有“正确”的方法。但是,我个人的偏好是创建 ViewModel 所依赖的简单接口 IMarshalledInvoker,它有一个方法可以在其他线程上调用某些操作。当我将 ViewModel 与 View 耦合时,我创建了一个 IMarshalledInvoker,它在后台使用 Dispatcher。使用这种模式,我仍然可以进行单元测试,仍然可以获得设计人员的支持,即它是很好的 MVVM ;-)
    • 嗯,好的,现在一切顺利。有趣的是,有一些不同的知识以我没有考虑过的方式相互关联。首先,我们知道创建一个线程安全的集合是很棘手的。我已经忘记了这一点,也没有在我的脑海中产生这种关联......基本上我只是在一个线程上添加。有趣的是,您忘记了自己为什么做事。因此,我认为答案的关键是将更改从多个线程集中到单个线程中。所以视图和视图模型之间只有一个通道??
    • 谢谢 Colin,当你添加你的评论时,我正在输入我的最后一条评论 :) Ricky Gervais 的猫叫 Colin,那不是你吗? ;)
    • 不完全。数据绑定框架实际上确实确保如果它收到有关属性更改的通知,它将在 UI 线程上设置实际控件的属性(甚至还有 DispatcherPriority.DataBinding 优先级)。这就是字符串文本绑定适用于 OP 的原因。问题是数据绑定框架没有 INotifyCollectionChanged 绑定。这就是为什么我们必须将对 ObservableCollection 的任何修改调用编组到 UI 线程。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-17
    • 2011-06-17
    • 2021-04-29
    • 2023-04-06
    • 2011-06-25
    • 2013-04-01
    相关资源
    最近更新 更多