31

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

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

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

{DynamicResource key}就像Connect错误报告一样,我正在使用SolidColorBrushResourceDictionary. 一些字典是手动加载的(用于主题支持)。我尝试手动冻结这些词典中的所有内容,但似乎没有帮助。

最近,当我在主窗口中添加了几个UserControls 并将其中的 ItemsControls 绑定到ObservableCollections 时,异常变得更加频繁。以前,我只会在 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 args)
       在 System.Windows.Freezable.FireChanged()
       在 System.Windows.Freezable.Freeze(布尔 isChecking)
       在 System.Windows.Freezable.Freeze()
       在 System.Windows.Freezable.System.Windows.ISealable.Seal()
       在 System.Windows.StyleHelper.SealIfSealable(对象值)
       在 System.Windows.StyleHelper.GetChildValueHelper(UncommonField`1 dataField,ItemStructList`1& valueLookupList,DependencyProperty dp,DependencyObject 容器,FrameworkObject 子项,Int32 childIndex,布尔样式查找,EffectiveValueEntry& 条目,ValueLookupType& sourceType,FrameworkElementFactory templateRoot)
       在 System.Windows.StyleHelper.GetChildValue(UncommonField`1 数据字段,DependencyObject 容器,Int32 childIndex,FrameworkObject 子项,DependencyProperty dp,FrugalStructList`1& childRecordFromChildIndex,EffectiveValueEntry& 条目,ValueLookupType& sourceType,FrameworkElementFactory templateRoot)
       在 System.Windows.StyleHelper.GetValueFromTemplatedParent(DependencyObject 容器、Int32 childIndex、FrameworkObject 子项、DependencyProperty dp、FrugalStructList`1& childRecordFromChildIndex、FrameworkElementFactory templateRoot、EffectiveValueEntry& 条目)
       在 System.Windows.FrameworkElement.GetValueFromTemplatedParent(DependencyProperty dp,EffectiveValueEntry& 条目)
       在 System.Windows.FrameworkElement.GetRawValue(DependencyProperty dp,PropertyMetadata 元数据,EffectiveValueEntry& 条目)
       在 System.Windows.FrameworkElement.EvaluateBaseValueCore(DependencyProperty dp,PropertyMetadata 元数据,EffectiveValueEntry & newEntry)
       在 System.Windows.DependencyObject.EvaluateEffectiveValue(EntryIndex entryIndex,DependencyProperty dp,PropertyMetadata 元数据,EffectiveValueEntry oldEntry,EffectiveValueEntry newEntry,OperationType operationType)
       在 System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex、DependencyProperty dp、PropertyMetadata 元数据、EffectiveValueEntry oldEntry、EffectiveValueEntry& newEntry、Boolean coerceWithDeferredReference、Boolean coerceWithCurrentValue、OperationType operationType)
       在 System.Windows.DependencyObject.InvalidateProperty(DependencyProperty dp)
       在 System.Windows.StyleHelper.InvalidateResourceDependentsForChild(DependencyObject 容器,DependencyObject 子项,Int32 childIndex,ResourcesChangeInfo 信息,FrameworkTemplate parentTemplate)
       在 System.Windows.TreeWalkHelper.InvalidateStyleAndReferences(DependencyObject d,ResourcesChangeInfo 信息,布尔 containsTypeOfKey)
       在 System.Windows.TreeWalkHelper.OnResourcesChanged(DependencyObject d,ResourcesChangeInfo 信息,布尔 raiseResourceChangedEvent)
       在 System.Windows.FrameworkElement.OnAncestorChangedInternal(TreeChangeInfo parentTreeState)
       在 System.Windows.TreeWalkHelper.OnAncestorChanged(DependencyObject d,TreeChangeInfo 信息)
       在 System.Windows.DescendentsWalker`1._VisitNode(DependencyObject d)
       在 MS.Internal.PrePostDescendentsWalker`1._VisitNode(DependencyObject d)
       在 System.Windows.DescendentsWalker`1.VisitNode(FrameworkElement fe)
       在 System.Windows.DescendentsWalker`1.VisitNode(DependencyObject d)
       在 System.Windows.DescendentsWalker`1.WalkFrameworkElementLogicalThenVisualChildren(FrameworkElement feParent, Boolean hasLogicalChildren)
       在 System.Windows.DescendentsWalker`1.IterateChildren(DependencyObject d)
       在 System.Windows.DescendentsWalker`1.StartWalk(DependencyObject startNode, Boolean skipStartNode)
       在 MS.Internal.PrePostDescendentsWalker`1.StartWalk(DependencyObject startNode, Boolean skipStartNode)
       在 System.Windows.TreeWalkHelper.InvalidateOnTreeChange(FrameworkElement fe,FrameworkContentElement fce,DependencyObject 父级,布尔 isAddOperation)
       在 System.Windows.FrameworkElement.OnVisualParentChanged(DependencyObject oldParent)
       在 System.Windows.Media.Visual.FireOnVisualParentChanged(DependencyObject oldParent)
       在 System.Windows.Media.Visual.RemoveVisualChild(视觉孩子)
       在 System.Windows.Media.VisualCollection.DisconnectChild(Int32 索引)
       在 System.Windows.Media.VisualCollection.Clear()
       在 System.Windows.Controls.UIElementCollection.ClearInternal()
       在 System.Windows.Controls.Panel.ClearChildren()
       在 System.Windows.Controls.Panel.OnItemsChangedInternal(对象发送者,ItemsChangedEventArgs 参数)
       在 System.Windows.Controls.Panel.OnItemsChanged(对象发送者,ItemsChangedEventArgs args)
       在 System.Windows.Controls.ItemContainerGenerator.OnRefresh()
       在 System.Windows.Controls.ItemContainerGenerator.OnCollectionChanged(对象发送者,NotifyCollectionChangedEventArgs 参数)
       在 System.Windows.Controls.ItemContainerGenerator.System.Windows.IWeakEventListener.ReceiveWeakEvent(类型 managerType,对象发送者,EventArgs e)
       在 System.Windows.WeakEventManager.DeliverEventToList(对象发送者,EventArgs 参数,ListenerList 列表)
       在 System.Windows.WeakEventManager.DeliverEvent(对象发送者,EventArgs 参数)
       在 System.Collections.Specialized.CollectionChangedEventManager.OnCollectionChanged(对象发送者,NotifyCollectionChangedEventArgs 参数)
       在 System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(对象发送者,NotifyCollectionChangedEventArgs e)
       在 System.Windows.Data.CollectionView.OnCollectionChanged(NotifyCollectionChangedEventArgs 参数)
       在 System.Windows.Controls.ItemCollection.System.Windows.IWeakEventListener.ReceiveWeakEvent(类型 managerType,对象发送者,EventArgs e)
       在 System.Windows.WeakEventManager.DeliverEventToList(对象发送者,EventArgs 参数,ListenerList 列表)
       在 System.Windows.WeakEventManager.DeliverEvent(对象发送者,EventArgs 参数)
       在 System.Collections.Specialized.CollectionChangedEventManager.OnCollectionChanged(对象发送者,NotifyCollectionChangedEventArgs 参数)
       在 System.Windows.Data.CollectionView.OnCollectionChanged(NotifyCollectionChangedEventArgs 参数)
       在 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,DependencyPropertyChangedEventArgs 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、EffectiveValueEntry& newEntry、Boolean coerceWithDeferredReference、Boolean coerceWithCurrentValue、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 集合视图,对象 newValue,布尔 isASubPropertyChange)
       在 MS.Internal.Data.ClrBindingWorker.OnSourcePropertyChanged(对象 o,字符串 propName)
       在 MS.Internal.Data.PropertyPathWorker.System.Windows.IWeakEventListener.ReceiveWeakEvent(类型 managerType,对象发送者,EventArgs e)
       在 System.Windows.WeakEventManager.DeliverEventToList(对象发送者,EventArgs 参数,ListenerList 列表)
       在 System.ComponentModel.PropertyChangedEventManager.OnPropertyChanged(对象发送者,PropertyChangedEventArgs 参数)
       在 c:\***\ViewModelBase.cs:line 17 中的 ***.ViewModelBase.OnPropertyChanged(String name)
    ......

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

4

3 回答 3

21

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

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

应改为:

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

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

于 2011-09-06T18:23:29.313 回答
3

我不相信有解决方法。根据我所读到的,在不得不自己处理这个问题时,WPF 会在创建时自动冻结资源。因此,无论何时您尝试在该资源上使用 DynamicResource,您都会得到可冻结的异常。

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

“WPF 将冻结样式或模板中的任何可冻结项。样式和模板可以在多个线程上使用,而可冻结项则不能,除非它们被冻结。我们目前正在考虑将其扩展到 Application.Resources 中的任何内容,因为那有同样的线程问题......冻结的可冻结对象上的 DynamicResource 不起作用,因为冻结的可冻结对象可能有多个父对象——因此我们将搜索资源的父对象是不明确的。”

于 2011-08-22T15:27:41.123 回答
0

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

<ItemsControl VirtualizingStackPanel.IsVirtualizing="False" />

只是尝试...

于 2011-08-22T14:34:41.393 回答