2011-08-22 14 views
27

He estado pegando un error WPF realmente malo recientemente. Creo que es lo mismo que this bug en Microsoft Connect.Solución alternativa para WPF ¿Error Freezable?

Nuestros objetivos de aplicaciones .NET 4.0 Client Profile utilizando Visual Studio 2010.

Básicamente, cuando un modelo de vista desencadena un cambio a cualquier propiedad o colección que hace que los elementos a moverse alrededor de un ItemsControl, hay una posibilidad de que la excepción a continuación se arrojará. No siempre sucede y parece suceder en función de diferentes factores desencadenantes en diferentes momentos. Parece ser más probable poco después de comenzar la aplicación. Si puede usarlo durante un par de minutos sin tocar la excepción, probablemente nunca golpee durante esa instancia de la aplicación.

Al igual que el informe de error de conexión, estoy usando {DynamicResource key} para cargar el SolidColorBrush es de un ResourceDictionary. Algunos de los diccionarios se cargan manualmente (para soporte de temas). Traté de congelar manualmente todo en esos diccionarios, pero no parece haber ayudado.

Las excepciones se han vuelto mucho más frecuentes últimamente cuando agregué un par más de UserControl s a la ventana principal que tienen ItemsControls en ellos vinculados a ObservableCollection s. Anteriormente, solo veía la excepción 1 vez de 50, pero ahora lo veo 4 de cada 5 veces que utilizo el programa.

¿Alguien tiene alguna idea para las soluciones? El error de Connect indica que esto probablemente se solucionará en la próxima versión de .NET (siempre que sea), pero este error está haciendo que nuestra aplicación sea básicamente inutilizable ahora.

 
    System.InvalidOperationException: Specified value of type 'System.Windows.Media.SolidColorBrush' must have IsFrozen set to false to modify. 
     at System.Windows.Freezable.WritePreamble() 
     at System.Windows.Freezable.remove_Changed(EventHandler value) 
     at System.Windows.ResourceReferenceExpression.ResourceReferenceExpressionWeakContainer.RemoveChangedHandler() 
     at System.Windows.ResourceReferenceExpression.ResourceReferenceExpressionWeakContainer.InvalidateTargetSubProperty(Object sender, EventArgs args) 
     at System.Windows.Freezable.FireChanged() 
     at System.Windows.Freezable.Freeze(Boolean isChecking) 
     at System.Windows.Freezable.Freeze() 
     at System.Windows.Freezable.System.Windows.ISealable.Seal() 
     at System.Windows.StyleHelper.SealIfSealable(Object value) 
     at System.Windows.StyleHelper.GetChildValueHelper(UncommonField`1 dataField, ItemStructList`1& valueLookupList, DependencyProperty dp, DependencyObject container, FrameworkObject child, Int32 childIndex, Boolean styleLookup, EffectiveValueEntry& entry, ValueLookupType& sourceType, FrameworkElementFactory templateRoot) 
     at System.Windows.StyleHelper.GetChildValue(UncommonField`1 dataField, DependencyObject container, Int32 childIndex, FrameworkObject child, DependencyProperty dp, FrugalStructList`1& childRecordFromChildIndex, EffectiveValueEntry& entry, ValueLookupType& sourceType, FrameworkElementFactory templateRoot) 
     at System.Windows.StyleHelper.GetValueFromTemplatedParent(DependencyObject container, Int32 childIndex, FrameworkObject child, DependencyProperty dp, FrugalStructList`1& childRecordFromChildIndex, FrameworkElementFactory templateRoot, EffectiveValueEntry& entry) 
     at System.Windows.FrameworkElement.GetValueFromTemplatedParent(DependencyProperty dp, EffectiveValueEntry& entry) 
     at System.Windows.FrameworkElement.GetRawValue(DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry& entry) 
     at System.Windows.FrameworkElement.EvaluateBaseValueCore(DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry& newEntry) 
     at System.Windows.DependencyObject.EvaluateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry newEntry, OperationType operationType) 
     at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType) 
     at System.Windows.DependencyObject.InvalidateProperty(DependencyProperty dp) 
     at System.Windows.StyleHelper.InvalidateResourceDependentsForChild(DependencyObject container, DependencyObject child, Int32 childIndex, ResourcesChangeInfo info, FrameworkTemplate parentTemplate) 
     at System.Windows.TreeWalkHelper.InvalidateStyleAndReferences(DependencyObject d, ResourcesChangeInfo info, Boolean containsTypeOfKey) 
     at System.Windows.TreeWalkHelper.OnResourcesChanged(DependencyObject d, ResourcesChangeInfo info, Boolean raiseResourceChangedEvent) 
     at System.Windows.FrameworkElement.OnAncestorChangedInternal(TreeChangeInfo parentTreeState) 
     at System.Windows.TreeWalkHelper.OnAncestorChanged(DependencyObject d, TreeChangeInfo info) 
     at System.Windows.DescendentsWalker`1._VisitNode(DependencyObject d) 
     at MS.Internal.PrePostDescendentsWalker`1._VisitNode(DependencyObject d) 
     at System.Windows.DescendentsWalker`1.VisitNode(FrameworkElement fe) 
     at System.Windows.DescendentsWalker`1.VisitNode(DependencyObject d) 
     at System.Windows.DescendentsWalker`1.WalkFrameworkElementLogicalThenVisualChildren(FrameworkElement feParent, Boolean hasLogicalChildren) 
     at System.Windows.DescendentsWalker`1.IterateChildren(DependencyObject d) 
     at System.Windows.DescendentsWalker`1.StartWalk(DependencyObject startNode, Boolean skipStartNode) 
     at MS.Internal.PrePostDescendentsWalker`1.StartWalk(DependencyObject startNode, Boolean skipStartNode) 
     at System.Windows.TreeWalkHelper.InvalidateOnTreeChange(FrameworkElement fe, FrameworkContentElement fce, DependencyObject parent, Boolean isAddOperation) 
     at System.Windows.FrameworkElement.OnVisualParentChanged(DependencyObject oldParent) 
     at System.Windows.Media.Visual.FireOnVisualParentChanged(DependencyObject oldParent) 
     at System.Windows.Media.Visual.RemoveVisualChild(Visual child) 
     at System.Windows.Media.VisualCollection.DisconnectChild(Int32 index) 
     at System.Windows.Media.VisualCollection.Clear() 
     at System.Windows.Controls.UIElementCollection.ClearInternal() 
     at System.Windows.Controls.Panel.ClearChildren() 
     at System.Windows.Controls.Panel.OnItemsChangedInternal(Object sender, ItemsChangedEventArgs args) 
     at System.Windows.Controls.Panel.OnItemsChanged(Object sender, ItemsChangedEventArgs args) 
     at System.Windows.Controls.ItemContainerGenerator.OnRefresh() 
     at System.Windows.Controls.ItemContainerGenerator.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args) 
     at System.Windows.Controls.ItemContainerGenerator.System.Windows.IWeakEventListener.ReceiveWeakEvent(Type managerType, Object sender, EventArgs e) 
     at System.Windows.WeakEventManager.DeliverEventToList(Object sender, EventArgs args, ListenerList list) 
     at System.Windows.WeakEventManager.DeliverEvent(Object sender, EventArgs args) 
     at System.Collections.Specialized.CollectionChangedEventManager.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args) 
     at System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(Object sender, NotifyCollectionChangedEventArgs e) 
     at System.Windows.Data.CollectionView.OnCollectionChanged(NotifyCollectionChangedEventArgs args) 
     at System.Windows.Controls.ItemCollection.System.Windows.IWeakEventListener.ReceiveWeakEvent(Type managerType, Object sender, EventArgs e) 
     at System.Windows.WeakEventManager.DeliverEventToList(Object sender, EventArgs args, ListenerList list) 
     at System.Windows.WeakEventManager.DeliverEvent(Object sender, EventArgs args) 
     at System.Collections.Specialized.CollectionChangedEventManager.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args) 
     at System.Windows.Data.CollectionView.OnCollectionChanged(NotifyCollectionChangedEventArgs args) 
     at System.Windows.Data.ListCollectionView.RefreshOverride() 
     at System.Windows.Data.CollectionView.Refresh() 
     at System.Windows.Data.CollectionView.EndDefer() 
     at System.Windows.Data.CollectionView.DeferHelper.Dispose() 
     at System.Windows.Controls.ItemCollection.SetCollectionView(CollectionView view) 
     at System.Windows.Controls.ItemCollection.SetItemsSource(IEnumerable value) 
     at System.Windows.Controls.ItemsControl.OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e) 
     at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e) 
     at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args) 
     at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType) 
     at System.Windows.DependencyObject.InvalidateProperty(DependencyProperty dp) 
     at System.Windows.Data.BindingExpressionBase.Invalidate(Boolean isASubPropertyChange) 
     at System.Windows.Data.BindingExpression.TransferValue(Object newValue, Boolean isASubPropertyChange) 
     at System.Windows.Data.BindingExpression.ScheduleTransfer(Boolean isASubPropertyChange) 
     at MS.Internal.Data.ClrBindingWorker.NewValueAvailable(Boolean dependencySourcesChanged, Boolean initialValue, Boolean isASubPropertyChange) 
     at MS.Internal.Data.PropertyPathWorker.UpdateSourceValueState(Int32 k, ICollectionView collectionView, Object newValue, Boolean isASubPropertyChange) 
     at MS.Internal.Data.ClrBindingWorker.OnSourcePropertyChanged(Object o, String propName) 
     at MS.Internal.Data.PropertyPathWorker.System.Windows.IWeakEventListener.ReceiveWeakEvent(Type managerType, Object sender, EventArgs e) 
     at System.Windows.WeakEventManager.DeliverEventToList(Object sender, EventArgs args, ListenerList list) 
     at System.ComponentModel.PropertyChangedEventManager.OnPropertyChanged(Object sender, PropertyChangedEventArgs args) 
     at ***.ViewModelBase.OnPropertyChanged(String name) in c:\***\ViewModelBase.cs:line 17 
    ..... 

EDIT: Hemos también trató simplemente suprimiendo cualquier InvalidOperationException s lanzadas dentro del evento PropertyChanged de nuestro modelo de vista de la clase base. Eso pareció reducir algo el número de excepciones, pero ahora solo las pulsamos en el evento ObservableCollectionCollectionChanged.

+0

¿Ha intentado subir OnPropertyChanged en su código con una prioridad diferente usando Dispatcher.Invoke - si es posible? A veces, es algo que utilizo para influenciar - un poco al azar, estoy de acuerdo :-) WPF en condiciones de carrera ... –

+2

Una suposición descabellada, pero ¿podrías congelar todos los recursos de pincel referenciados en el diccionario en su creación de instancias? Puede leer cómo hacerlo aquí: http://stackoverflow.com/questions/799890/how-can-wpf-objects-deriving-from-freezable-be-frozen-in-xaml –

+0

Además, ¿se ha asegurado de que ¿Solo está modificando el ObservableCollection desde el hilo de UI? –

Respuesta

20

Para solucionar este error de .net, cambie todos los Pinceles de color sólido de su código para que se pueda congelar.Por ejemplo

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

se debe cambiar a:

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

Para más instrucciones detalladas ver aquí: How can WPF objects deriving from Freezable be frozen in XAML?.

+0

¡Parece que lo ha solucionado! Supongo que mi congelación manual al cargar los diccionarios no funcionaba por completo. –

+0

¡increíble! cuán simple, me ayudó por completo. –

+2

me pregunto qué es "po:"? – tofutim

0

Cada vez que se trata de comportamiento de errores alrededor de MVVM con ItemsControl y controles derivados, mi primer intento es deshabilitar VirtualizingStackPanel.

<ItemsControl VirtualizingStackPanel.IsVirtualizing="False" /> 

Sólo una oportunidad ...

+1

Lo probé y configuré esto en cada ComboBox/ItemsControl/ListBox en la aplicación. No parece hacer la diferencia. –

3

No creo que hay un trabajo en torno a esto. Al tener que lidiar con esto yo mismo, por lo que he leído, WPF autocongela recursos en la creación. Por lo tanto, cada vez que intente utilizar DynamicResource en ese recurso obtendrá la excepción de freezable.

Aquí es una cita del equipo de Microsoft Fundación sobre lo que está ocurriendo:.

"WPF se congelará cualquier freezables dentro de un estilo o una plantilla Estilos y plantillas se pueden utilizar en varios subprocesos, y freezables puede' t a menos que estén congelados. Actualmente estamos considerando extender esto a cualquier cosa que se ponga dentro de Application.Resources, ya que tiene el mismo problema de subprocesamiento ... DynamicResource en un congelable congelable no funciona, porque un freezable congelado potencialmente tiene múltiples padres, por lo que es ambiguo que padre busquemos el r esource ".

+0

'DynamicResource's que hacen referencia a trabajos congelados' Freezable'- la aplicación se inicia y funciona bien la mayor parte del tiempo. Los recursos a los que me refiero son solo cosas como pinceles que no tienen ninguna búsqueda de recursos dinámicos o estáticos dentro de ellos. Todos se ven así: '' Además, por lo que puedo decir, WPF no parece congelar automáticamente las cosas inmediatamente cuando se carga el diccionario. Es por eso que los congelo manualmente. –

Cuestiones relacionadas