.net 无法在CollectionChanged事件TPL期间更改ObservableCollection
当我在按钮单击处理程序中对ObservableCollection调用.Clear()时,我会间歇性地遇到此错误。我感到困惑,因为我确实有其他TPL任务正在运行,但所有这些任务都通过以下方式更新ObservableCollection:.net 无法在CollectionChanged事件TPL期间更改ObservableCollection,.net,wpf,task-parallel-library,observablecollection,.net,Wpf,Task Parallel Library,Observablecollection,当我在按钮单击处理程序中对ObservableCollection调用.Clear()时,我会间歇性地遇到此错误。我感到困惑,因为我确实有其他TPL任务正在运行,但所有这些任务都通过以下方式更新ObservableCollection: mainWindow.Dispatcher.Invoke(new Action(delegate() { this.myCollection.Add(myItem); })); essense中的dispatcher是否使我的ObservableCollec
mainWindow.Dispatcher.Invoke(new Action(delegate()
{
this.myCollection.Add(myItem);
}));
essense中的dispatcher是否使我的ObservableCollection线程安全,因为所有操作都是主UI线程上的原子操作?顺便说一句:我还更新了Dispatchermer中集合成员的一些字段,但没有在timer.tick处理程序中删除或向集合添加项
詹姆斯:
我创建了一个示例应用程序来隔离问题,但在示例中一切正常。因此,我的应用程序中的其他内容一定是在另一个线程上更改了集合。
这一切都很好,您可以。无误清除:
<Window x:Class="WpfApplication1.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">
<StackPanel>
<Button Name="clear" Height="23" Click="clear_Click"></Button>
<ListBox ItemsSource="{Binding MyCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
公共部分类主窗口:窗口
{
私有调度程序myTimer=null;
公共主窗口()
{
初始化组件();
this.DataContext=this;
已加载+=新路由EventHandler(主窗口已加载);
}
private bool isLoaded=false;
已加载无效主窗口(对象发送器、路由目标)
{
如果(已加载)返回;
isLoaded=true;
var task=新任务(()=>AddObjectsTask());
task.Start();
myTimer=新的调度程序();
myTimer.Interval=新的时间跨度(0,0,1);
myTimer.Tick+=新事件处理程序(myTimer\u Tick);
myTimer.Start();
_MyCollection.CollectionChanged+=新系统.Collections.Specialized.NotifyCollectionChangedEventHandler(\u MyCollection\u CollectionChanged);
}
void\u MyCollection\u CollectionChanged(对象发送方,System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if(e.Action==System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
var query=(从_myCollectionselect n.ToList()中的n开始);
if(query.Any())
{
foreach(查询中的someobjecto)
{
o、 Name=(Convert.ToInt64(o.Name)+1.ToString();
}
}
}
}
void myTimer_Tick(对象发送方,事件参数e)
{
这个._MyCollection.Add(newsomeObject(){Name=99.ToString()});
}
void AddObjectsTask()
{
int i=0;
while(true)
{
睡眠(10);
this.Dispatcher.Invoke(新操作(委托)()
{
这个._MyCollection.Add(newsomeObject(){Name=i.ToString()});
}));
i++;
}
}
私有无效清除\单击(对象发送者,路由目标e)
{
_MyCollection.Clear();
}
私有ObservableCollection_MyCollection=新ObservableCollection();
公共可观测集合MyCollection
{
得到
{
返回_MyCollection;
}
}
}
公共类SomeObject:INotifyPropertyChanged
{
#区域inotifyproperty已更改
公共事件属性更改事件处理程序属性更改;
public void NotifyPropertyChanged(字符串信息)
{
if(PropertyChanged!=null)
{
PropertyChanged(此,新PropertyChangedEventArgs(信息));
}
}
#端区
私有字符串_Name=string.Empty;
公共字符串名
{
得到
{
返回_Name;
}
设置
{
_名称=值;
NotifyPropertyChanged(“名称”);
}
}
}
请包含修改集合和异常信息的其他代码。另外,如果要在timer tick中修改集合列表成员的属性,并且这些属性是绑定到UI控件的数据,请为UI框架(WPF?)添加标记,如果您没有将其封送到正确的线程,某些UI框架将抛出。似乎在我的\u CollectionChanged事件处理程序中,我正在剥离显示进度对话框的第三方组件。一旦我关闭了显示进度的选项,就不会再有错误了。不知道发生了什么。如果这对我的主窗口调度器有什么影响?
public partial class MainWindow : Window
{
private DispatcherTimer myTimer = null;
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
Loaded +=new RoutedEventHandler(MainWindow_Loaded);
}
private bool isLoaded = false;
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
if (isLoaded) return;
isLoaded = true;
var task = new Task(() => AddObjectsTask());
task.Start();
myTimer = new DispatcherTimer();
myTimer.Interval = new TimeSpan(0, 0, 1);
myTimer.Tick += new EventHandler(myTimer_Tick);
myTimer.Start();
_MyCollection.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(_MyCollection_CollectionChanged);
}
void _MyCollection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
var query = (from n in _MyCollection select n).ToList();
if (query.Any())
{
foreach (SomeObject o in query)
{
o.Name = (Convert.ToInt64(o.Name) + 1).ToString();
}
}
}
}
void myTimer_Tick(object sender, EventArgs e)
{
this._MyCollection.Add(new SomeObject() { Name = 99.ToString() });
}
void AddObjectsTask()
{
int i = 0;
while(true)
{
Thread.Sleep(10);
this.Dispatcher.Invoke(new Action(delegate()
{
this._MyCollection.Add(new SomeObject() { Name = i.ToString() });
}));
i++;
}
}
private void clear_Click(object sender, RoutedEventArgs e)
{
_MyCollection.Clear();
}
private ObservableCollection<SomeObject> _MyCollection = new ObservableCollection<SomeObject>();
public ObservableCollection<SomeObject> MyCollection
{
get
{
return _MyCollection;
}
}
}
public class SomeObject : INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#endregion
private string _Name = string.Empty;
public string Name
{
get
{
return _Name;
}
set
{
_Name = value;
NotifyPropertyChanged("Name");
}
}
}