我可以更改从另一个线程更改 ObservableCollections 后触发的 OnCollectionChanged 事件的顺序吗?
Posted
技术标签:
【中文标题】我可以更改从另一个线程更改 ObservableCollections 后触发的 OnCollectionChanged 事件的顺序吗?【英文标题】:Can I change the order of OnCollectionChanged events firing after changes to ObservableCollections from another thread? 【发布时间】:2021-10-16 16:05:38 【问题描述】:我有一个 MVVM 应用程序。我有保存我的模型的 ObservableCollections。如果 OnCollectionChanged 被触发并且我们有“添加”事件,那么我将项目插入到我的数据库中。
我有一个从文件中读取数据、创建模型并将它们添加到集合中的函数。由于我的数据库中的关系,我必须按特定顺序添加它们。
例子:
邮政(邮政编号、邮政编号、邮政城镇) 性别(性别ID、性别) 人员(姓名、姓氏、职位 ID、性别 ID)所以我会首先制作 Post 模型,将它们添加到 ObservableCollection,然后触发 OnCollectionChanged 触发插入。然后我会添加 Gender 模型,然后是 Person 模型。所以首先所有 ObservableCollection
我想将此导入移至后台。我使用的是一个异步命令,它可以生成锁、设置 BindingOperations.EnableCollectionSynchronization 并运行 Task.Run。在任务中,我调用了一个读取文件并在对象中返回数据的方法和第二个 void 方法,该方法使用锁将数据插入到 ObservableCollections 中。
我遇到的问题是线程完成后,主线程交替触发 OnCollectionChanged 事件:
添加了一个 Post 模型 -> 触发 OnCollectionChanged 添加了一个性别模型 -> 触发 OnCollectionChanged 添加了一个人 -> 触发 OnCollectionChanged 添加了一个 Post 模型 添加了一个性别模型 添加了一个人 等等……这会导致错误,因为它尝试插入尚未插入 Gender 模型和 Post 模型的 Person 模型。这是预期的行为吗?我可以更改这些事件的触发顺序吗?
【问题讨论】:
我认为它的设计很糟糕...您将 DTO 与业务对象混合...Post
应该有字段 Person
和 Person
应该有字段 Gender
然后会有没问题...此外,您可以使用 Guid
s 作为 id,因此您可以在插入数据库之前选择它们
我确实在插入之前给出了 ID。在数据库中插入时会引发错误,因为表包含关系并且它尝试将关系插入到尚不存在的记录。 Person 必须与 Post 有关系,因为它指的是每个 Person 的地址。
在我看来,您的问题的更深层原因是 ViewModel 和 Model 之间的功能分离混淆。更改真实数据是模型的功能。 ViewModel 中的 observable 集合只是真实数据的反映。 “添加帖子”事件发生在模型中。在此事件中,您必须将包含所有数据的 DTO 实例发送到 ViewModel。但是除非你有一个人来填写帖子中的所有链接,否则你不能形成 DTO 帖子。
因此,在Model中,首先形成一个DTO Person,用这个DTO创建一个事件。在此事件中,VM 将其添加到其集合中,并且集合更新也被编组到那里的 UI 线程。然后模型创建 DTO Post 的一个实例,为其创建一个事件等。
【参考方案1】:
您可以将添加的内容放在一个任务中或让任务按顺序开始,而不是同时添加所有内容。
Task.Run(() =>
AddPosts();
AddGenders();
AddPersons();
这种方式是异步的,但顺序正确。
【讨论】:
此实现不保证正确的工作顺序。您忽略了这样一个事实,即当可观察集合异步更改时,必须将 CollectionChanged 事件编组到主 UI 线程。这种封送处理是异步发生的。并且不能保证编组第一个事件会比编组下一个事件更快。以上是关于我可以更改从另一个线程更改 ObservableCollections 后触发的 OnCollectionChanged 事件的顺序吗?的主要内容,如果未能解决你的问题,请参考以下文章