C# 为什么取消订阅DataContextChanged会由于集合已修改而导致InvalidOperation异常
我最近在silverlight中偶然发现了一个使用datacontext changed事件的问题 如果您订阅了更改的事件,然后立即取消订阅,则会引发异常C# 为什么取消订阅DataContextChanged会由于集合已修改而导致InvalidOperation异常,c#,silverlight,C#,Silverlight,我最近在silverlight中偶然发现了一个使用datacontext changed事件的问题 如果您订阅了更改的事件,然后立即取消订阅,则会引发异常 DataContextChanged += MainPage_DataContextChanged; void MainPage_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { var vm = e.NewValue as VM; if
DataContextChanged += MainPage_DataContextChanged;
void MainPage_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var vm = e.NewValue as VM;
if(vm != null)
{
DataContextChange-= MainPage_DataContextChanged;//throws invalidoperationexception for collection modified
}
}
为了解决这个问题,我只是在晚些时候取消订阅活动,在这种情况下,要求提前取消订阅,而不是晚些,这样就行了
DataContextChanged += MainPage_DataContextChanged;
void MainPage_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var vm = e.NewValue as VM;
if(vm != null)
{
//forces item onto the dispatcher queue so anything needing to happen with 'collections' happens first
Dispatcher.BeginInvoke(()=>
{
DataContextChange-= MainPage_DataContextChanged;//throws invalidoperationexception for collection modified
});
}
}
我猜集合是可视化树中所有不同控件的子元素,我猜它们的更新可能发生在调度程序队列上,所以我的问题是:
为什么在事件触发后取消订阅会影响在此之后要修改或更新的集合
编辑:
在考虑过这一点之后,这是否与在完成之前修改的事件处理程序调用列表有关?您对修改的调用列表的怀疑是正确的 根据dotPeek的反编译,以下是触发DataContextChanged事件的代码:
private void RaisePublicDataContextChanged()
{
if (this._dataContextChangedInfo == null)
return;
object oldValue = this._dataContextChangedInfo.OldValue;
object dataContext = this.DataContext;
if (oldValue == dataContext)
return;
this._dataContextChangedInfo.OldValue = dataContext;
List<DependencyPropertyChangedEventHandler>.Enumerator enumerator = this._dataContextChangedInfo.ChangedHandlers.GetEnumerator();
try
{
// ISSUE: explicit reference operation
while (((List<DependencyPropertyChangedEventHandler>.Enumerator) @enumerator).MoveNext())
{
// ISSUE: explicit reference operation
((List<DependencyPropertyChangedEventHandler>.Enumerator) @enumerator).get_Current()((object) this, new DependencyPropertyChangedEventArgs(FrameworkElement.DataContextProperty, oldValue, dataContext));
}
}
finally
{
enumerator.Dispose();
}
}
private void RaisePublicDataContextChanged()
{
if(this.\u dataContextChangedInfo==null)
返回;
object oldValue=此。_dataContextChangedInfo.oldValue;
对象dataContext=this.dataContext;
if(oldValue==dataContext)
返回;
这._dataContextChangedInfo.OldValue=dataContext;
List.Enumerator Enumerator=this._dataContextChangedInfo.ChangedHandlers.GetEnumerator();
尝试
{
//问题:显式引用操作
while(((List.Enumerator)@Enumerator.MoveNext())
{
//问题:显式引用操作
((List.Enumerator)@Enumerator.get_Current()((对象)此,新的DependencyPropertyChangedEventArgs(FrameworkElement.DataContextProperty,oldValue,dataContext));
}
}
最后
{
枚举数。Dispose();
}
}
如您所见,代码使用枚举器在处理程序集合中进行迭代。因此,当您在调用处理程序期间取消订阅事件时,您正在使枚举数无效,从而导致您看到的异常。是否收到包含该异常的消息?