我正在构建一个应用程序,它使用许多ItemControls(datagrids和listviews) . 为了从后台线程轻松更新这些列表,我将此扩展用于ObservableCollections,它运行良好:
今天我安装了VS12(后来安装了.NET 4.5),因为我想使用为.NET 4.5编写的组件 . 在将我的项目升级到.NET 4.5(从4.0)之前,我的数据网格从workerthread更新时开始抛出InvalidOperationException . 异常消息:
抛出此异常是因为控件'System.Windows.Controls.DataGrid Items.Count:5'的名称为'(未命名)'的生成器已收到与Items集合的当前状态不一致的CollectionChanged事件序列 . 检测到以下差异:累计计数4与实际计数5不同 . [累计计数为(上次重置时计数#Adds - 自上次重置后自上次复位) .
Repro代码:
XAML:
<Window x:Class="Test1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid ItemsSource="{Binding Items, Mode=OneTime}" PresentationTraceSources.TraceLevel="High"/>
</Grid>
</Window>
码:
public partial class MainWindow : Window
{
public ExtendedObservableCollection<int> Items { get; private set; }
public MainWindow()
{
InitializeComponent();
Items = new ExtendedObservableCollection<int>();
DataContext = this;
Loaded += MainWindow_Loaded;
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(() =>
{
foreach (var item in Enumerable.Range(1, 500))
{
Items.Add(item);
}
});
}
}
4 回答
WPF 4.5提供了一些访问非UI线程上的集合的新功能 .
这可以通过在
BindingOperations
类上使用静态方法EnableCollectionSynchronization来完成 .用法如下 . 创建一个对象,该对象用作集 Contract 步的锁 . 然后调用BindingsOperations的EnableCollectionSynchronization方法,并将要同步的集合和用于锁定的对象传递给它 .
我已更新您的代码并添加了详细信息 . 此外,我将集合更改为正常的ObservableCollection以避免冲突 .
另见:http://10rem.net/blog/2012/01/20/wpf-45-cross-thread-collection-synchronization-redux
总结此主题,此
AsyncObservableCollection
适用于.NET 4和.NET 4.5 WPF应用程序 .Jehof的答案是正确的 .
我们还无法定位4.5,并且我们的自定义可观察集合已经允许后台更新(在事件通知期间使用Dispatcher)存在此问题 .
如果有人发现它有用,我在我们的应用程序中使用了以下代码,它们以.NET 4.0为目标,使其能够在执行环境为.NET 4.5时使用此功能:
这适用于 Windows 10 Version 1607 用户使用可能存在此问题的 VS 2017 的发布版本 .
你不需要 lock 也不需要 EnableCollectionSynchronization .