WPF可冻结错误的解决方法



我最近遇到了一个非常糟糕的WPF错误。我认为这与Microsoft Connect上的这个错误相同。

我们的应用程序以使用Visual Studio 2010的.NET 4.0客户端配置文件为目标。

基本上,当ViewModel触发对任何属性或集合的更改,导致项目在ItemsControl中移动时,可能会引发下面的异常。它并不总是发生,而且似乎是基于不同的触发因素——不同的时间。它似乎更有可能在启动应用程序后不久出现。如果您可以在不碰到异常的情况下使用它几分钟,那么在该应用程序实例期间可能永远不会碰到异常。

与Connect错误报告一样,我使用{DynamicResource key}ResourceDictionary加载SolidColorBrushes。有些字典是手动加载的(为了支持主题化)。我试着手动冻结那些词典中的所有内容,但似乎没有帮助。

最近,当我在主窗口中添加了几个将ItemsControls绑定到ObservableCollections的UserControls时,异常变得更加频繁。以前,我只会在50次中看到1次异常,但现在我使用该程序时,在5次中看到4次异常。

有人有解决办法的想法吗?Connect错误表明这可能会在下一个.NET版本中得到修复(无论何时),但这个错误使我们的应用程序现在基本上无法使用。

System.InvalidOperationException:类型为"System.Windows.Media.SolidColorBrush"的指定值必须将IsFrozen设置为false才能修改。位于System.Windows.Freezable.WritePreamble()位于System.Windows.Freezable.remove_Changed(EventHandler值)位于System.Windows.ResourceReferenceExpression.ResourceReferenceExpressionWeakContainer.RemoveChangedHandler()位于System.Windows.ResourceReferenceExpression.ResourceReferenceExpressionWeakContainer.InvalidateTargetSubProperty(对象发送方,EventArgs参数)位于System.Windows.Freezable.FireChanged()位于System.Windows.Freezable.Freeze(布尔值为Checking)位于System.Windows.Freezable.Freeze()位于System.Windows.Freezable.System.Windows.ISeallable.Sil()位于System.Windows.StyleHelper.SealfSeaable(对象值)位于System.Windows.StyleHelper.GetChildValueHelper(UncommonField`1 dataField,ItemStructList`1&valueLookupList,DependencyProperty dp,Dependency Object容器,FrameworkObject子级,Int32子级索引,布尔样式查找,EffectiveValueEntry&entry,ValueLookupType&sourceType,FrameworkElementFactory templateRoot)位于System.Windows.StyleHelper.GetChildValue(UncommonField`1 dataField,DependencyObject容器,Int32 childIndex,FrameworkObject子级,Dependency Property dp,FrugalStructList`1&childRecordFromChildIndex,EffectiveValueEntry&entry,ValueLookupType&sourceType,FrameworkElementFactory templateRoot)位于System.Windows.StyleHelper.GetValueFromTemplatedPrent(DependencyObject容器,Int32子级索引,FrameworkObject子级,DependencyProperty dp,FrugalStructList`1&childRecordFromChildIndex,FrameworkElementFactory templateRoot,EffectiveValueEntry&entry)位于System.Windows.FrameworkElement.GetValueFromTemplatedPrent(DependencyProperty dp,EffectiveValueEntry&entry)位于System.Windows.FrameworkElement.GetRawValue(DependencyProperty dp,PropertyMetadata元数据,EffectiveValueEntry&entry)位于System.Windows.FrameworkElement.EEvaluateBaseValueCore(DependencyProperty dp、PropertyMetadata元数据、EffectiveValueEntry和newEntry)位于System.Windows.DependencyObject.EEvaluateEffectiveValue(EntryIndex EntryIndex、DependencyProperty dp、PropertyMetadata元数据、EffectiveValueEntry oldEntry、EffectiveValue Entry newEntry、OperationType OperationType)位于System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex EntryIndex、DependencyProperty dp、PropertyMetadata元数据、EffectiveValueEntry oldEntry、EffectiveValue Entry&newEntry、布尔强制DeferredReference、布尔强制CurrentValue、OperationType OperationType)位于System.Windows.DependencyObject.InvalidateProperty(DependencyProperty dp)位于System.Windows.StyleHelper.InvalidateResourceDependentsForChild(DependencyObject容器,DependencyObject子级,Int32子级索引,ResourcesChangeInfo,FrameworkTemplate父级模板)位于System.Windows.TreeWalkHelper.InvalidateStyleAndReferences(DependencyObject d,ResourcesChangeInfo,Boolean containsTypeOfKey)位于System.Windows.TreeWalkHelper.OnResourcesChanged(DependencyObject d,ResourcesChangeInfo,Boolean raiseResourceChangedEvent)位于System.Windows.FrameworkElement.OnAcestorChangedInternal(TreeChangeInfo parentTreeState)位于System.Windows.TreeWalkHelper.OnAncestorChanged(DependencyObject d,TreeChangeInfo信息)位于System.Windows.DescendantsWalker`1._VisitNode(DependencyObject d)位于MS.Internal.PrePostDescendentsWalker`1._VisitNode(DependencyObject d)位于System.Windows.DescendantsWalker`1.VisitNode(FrameworkElement fe)位于System.Windows.DescendantsWalker`1.VisitNode(DependencyObject d)位于System.Windows.DescendantsWalker`1.WalkFrameworkElementLogicalThenVisualChildren(FrameworkElement feParent,Boolean hasLogicalChildren)位于System.Windows.DescendantsWalker`1.IterateChildren(DependencyObject d)位于System.Windows.DescendantsWalker`1.StartWalk(DependencyObject startNode,Boolean skipStartNode)位于MS.Internal.PrePostDescendantsWalker`1.StartWalk(DependencyObject startNode,Boolean skipStartNode)位于System.Windows.TreeWalkHelper.InvalidateOnTreeChange(FrameworkElement fe,FrameworkContentElement fce,DependencyObject父级,Boolean isAddOperation)位于System.Windows.FrameworkElement.OnVisualParentChanged(DependencyObject oldParent)位于System.Windows.Media.Vision.FireOnVisualParentChanged(DependencyObject oldParent)位于System.Windows.Media.Vindows.RemoveVisualChild(Visual子级)位于System.Windows.Media.VVisualCollection.DisconnectChild(Int32索引)位于System.Windows.Media.VVisualCollection.Clear()位于System.Windows.Controls.UIElementCollection.ClearInternal()位于System.Windows.Controls.Panel.ClearChildren()位于System.Windows.Controls.Panel.OnItemsChangedInternal(对象发送器,ItemsChangedEventArgs参数)位于System.Windows.Controls.Panel.OnItemsChanged(对象发送器,ItemsChangedEventArgs参数)位于System.Windows.Controls.ItemContainerGenerator.OnRefresh()位于System.Windows.Controls.ItemContainerGenerator.OnCollectionChanged(对象发送器,NotifyCollectionChangedEventArgs参数)位于System.Windows.Controls.ItemContainerGenerator.System.Windows.IWeakEventListener.ReceiveWeakEvent(类型managerType,Object sender,EventArgs e)位于System.Windows.WeakEventManager.EDeliverEventToList(对象发送方、EventArgs参数、ListerList列表)位于System.Windows.WeakEventManager.EDeliverEvent(对象发送方,EventArgs参数)位于System.Collections.Specialized.CollectionChangedEventManager.OnCollectionChanged(对象发送方,NotifyCollectionChangedPEventArgs参数)位于System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(对象发送方,NotifyCollectionChangedEventArgs e)位于System.Windows.Data.CollectionView.OnCollectionChanged(NotifyCollectionChangedEventArgs args)位于System.Windows.Controls.ItemCollection.System.Windows.IWeakEventListener.ReceiveWeakEvent(类型managerType,Object sender,EventArgs e)位于System.Windows.WeakEventManager.EDeliverEventToList(对象发送方、EventArgs参数、ListerList列表)位于System.Windows.WeakEventManager.EDeliverEvent(对象发送方,EventArgs参数)位于System.Collections.Specialized.CollectionChangedEventManager.OnCollectionChanged(对象发送方,NotifyCollectionChangedPEventArgs参数)位于System.Windows.Data.CollectionView.OnCollectionChanged(NotifyCollectionChangedEventArgs args)位于System.Windows.Data.ListCollectionView.RefreshOverride()位于System.Windows.Data.CollectionView.Refresh()位于System.Windows.Data.CollectionView.EndDefer()位于System.Windows.Data.CollectionView.DeferHelper.Dispose()位于System.Windows.Controls.ItemCollection.SetCollectionView(CollectionView视图)位于System.Windows.Controls.ItemCollection.SetItemsSource(IEnumerable值)位于System.Windows.Controls.ItemsControl.OnItemsSourceChanged(DependencyObject d,DependencyProperty ChangedEventArgs e)位于System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)位于System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)位于System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs参数)位于System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex EntryIndex、DependencyProperty dp、PropertyMetadata元数据、EffectiveValueEntry oldEntry、EffectiveValue Entry&newEntry、布尔强制DeferredReference、布尔强制CurrentValue、OperationType OperationType)位于System.Windows.DependencyObject.InvalidateProperty(DependencyProperty dp)位于System.Windows.Data.BindingExpressionBase.Invalidate(布尔值isASubPropertyChange)位于System.Windows.Data.BindingExpression.TransferValue(对象newValue,布尔值isASubPropertyChange)位于System.Windows.Data.BindingExpression.ScheduleTransfer(布尔值isASubPropertyChange)位于MS.Internal.Data.ClrBindingWorker.NewValueAvailable(布尔依赖资源更改,布尔初始值,布尔isASubPropertyChange)位于MS.Internal.Data.PropertyPathWorker.UpdateSourceValueState(Int32 k,ICollectionView collectionView,Object newValue,Boolean isASubPropertyChange)位于MS.Internal.Data.ClrBindingWorker.OnSourcePropertyChanged(对象o,字符串propName)位于MS.Internal.Data.PropertyPathWorker.System.Windows.IWeakEventListener.ReceiveWeakEvent(类型managerType,Object sender,EventArgs e)位于System.Windows.WeakEventManager.EDeliverEventToList(对象发送方、EventArgs参数、ListerList列表)位于System.ComponentModel.PropertyChangedEventManager.OnPropertyChanged(对象发送器,PropertyChangedEventArgs参数)位于c:\***\ViewModelBase.cs:line 17中的***.ViewModelBase.OnPropertyChanged(字符串名称)…..

编辑:我们还尝试过简单地抑制在ViewModel基类的PropertyChanged事件中抛出的任何InvalidOperationException。这似乎在一定程度上减少了异常的数量,但现在我们只是在ObservableCollectionCollectionChanged事件中遇到了它们。

要解决这个.net错误,请将代码中的所有纯色画笔更改为可冻结。例如

<SolidColorBrush x:Key="WindowBackground" Color="Black" />

应更改为:

<SolidColorBrush po:Freeze="True" x:Key="WindowBackground" Color="Black" />. 

有关更详细的说明,请参阅此处:如何在XAML中冻结从Freezable派生的WPF对象?。

我不认为有解决办法。根据我所读到的内容,WPF在创建时会自动冻结资源。因此,每当您尝试在该资源上使用DynamicResource时,都会得到可冻结的异常。

以下是微软基金会团队对正在发生的事情的引用:

"WPF将冻结样式或模板中的任何freezables。样式和模板可以在多个线程上使用,而freezables不能,除非它们被冻住了。我们目前正在考虑将其扩展到任何内容放入Application.Resources中,因为它具有相同的线程问题冻结的freezable上的DynamicResource不起作用,因为一个冻结的freezable可能有多个父对象,所以它不清楚我们将搜索哪个父级资源">

每次涉及到带有ItemsControl和派生控件的MVVM的错误行为时,我的第一个尝试就是禁用VirtualizingStackPanel。

<ItemsControl VirtualizingStackPanel.IsVirtualizing="False" />

只是一次尝试。。。

最新更新