BindingOperations.EnableCollectionSynchronization调用线程无法访问此对象



我知道这方面已经有很多问题了,但我似乎对BindingOperations.EnableCollectionSynchronization(observableC,挂锁(;作品

我有一个使用mvvm的WPF应用程序,在我的视图模型中,我想更新我的ObservaleCollection。

经过一些谷歌搜索,我找到了imo应该工作的解决方案:第一次调用它很好,但睡了1分钟后,它给了我这个:

System.NotSupportedException:"此类型的CollectionView不支持从不同于Dispatcher线程的线程更改其SourceCollection。">

public MainViewModel()
{
MainOc= new ObservableCollection<DataModel>();
MainView= CollectionViewSource.GetDefaultView(MainOc);
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
BindingOperations.EnableCollectionSynchronization(MainOc, padlock);
BindingOperations.EnableCollectionSynchronization(MainView, padlock);
}));

Task.Run(() => GetData());
}
private async void GetData()
{
while (true)
{
lock (padlock)
{
MainOc.Clear();
}

foreach (DataRow row in tempTable.Rows)
{
lock (padlock) {
MainOc.Add(new DataModel());
}
}
lock (padlock)
{
MainView= CollectionViewSource.GetDefaultView(MainOc);
}
Thread.Sleep(TimeSpan.FromMinutes(1));
}
}

我怀疑Application.Current.Dispatcher.BeginInvoke,因为它稍后会在UI线程上运行。假定构造函数已经在UI线程上运行,因此此代码将被放置在UI线程计划执行的任务队列的最后一个。EnableCollectionSynchronization的文档说明

  • 调用必须发生在UI线程上。

  • 调用必须在其他线程上使用集合之前进行,或者在将集合附加到ItemsControl之前进行,以较晚者为准。

我不确定后面的要点是否实现。我希望订单是这样的:

  1. MainViewModel((正在运行
  2. GetData((开始更新集合(在后台线程上(
  3. 视图模型已附着到视图
  4. BindingOperations.EnableCollectionSynchronization被调用

所以我至少会尝试直接调用BindingOperations.EnableCollectionSynchronization,而不使用BeginInvoke。或者至少,放置一些断点或日志记录,以验证在附加视图模型之前是否调用了EnableCollectionSynchronization

在任何情况下,我可能都不建议使用那种同步机制。我的建议是:

  1. 使用调度计时器每分钟调用一次UI线程上的方法
  2. 如果方法执行任何缓慢的操作,如从数据库中获取数据,请使该方法异步,然后执行异步数据库调用,或者在返回结果的后台线程上执行同步数据库调用。无论哪种情况,都应等待通话
  3. 获得数据后,请更新集合以更新UI。此代码将在UI线程上运行,即使您在后台线程上等待工作,也不需要同步

最新更新