J'ai récemment frappé un bug WPF vraiment mauvais. Je pense que c'est la même chose que this bug sur Microsoft Connect.Solution de contournement pour bug WPF Freezable?
Nos cibles d'application .NET 4.0 Profil client à l'aide de Visual Studio 2010.
En fait, lorsqu'un ViewModel déclenche un changement d'une propriété ou d'une collection qui cause des éléments à se déplacer dans un ItemsControl, il y a une chance que l'exception ci-dessous sera jeté. Cela n'arrive pas toujours et semble se produire en fonction de différents déclencheurs différents temps. Il semble être plus probable peu après le démarrage de l'application. Si vous pouvez l'utiliser pendant quelques minutes sans toucher à l'exception, vous ne frapperez probablement jamais pendant cette instance d'application. Comme le rapport de bogue Connect, j'utilise {DynamicResource key}
pour charger le SolidColorBrush
es à partir d'un ResourceDictionary
. Certains dictionnaires sont chargés manuellement (pour le support thématique). J'ai essayé de tout geler manuellement dans ces dictionnaires, mais cela ne semble pas avoir aidé.
Les exceptions sont devenues beaucoup plus fréquentes ces derniers temps quand j'ai ajouté un couple plus UserControl
s à la fenêtre principale qui a ItemsControls dans eux lié à ObservableCollection
s. Auparavant, je ne voyais que l'exception 1 fois sur 50, mais maintenant je la vois 4 fois sur 5 j'utilise le programme.
Est-ce que quelqu'un a des idées pour des solutions de contournement? Le bogue de Connect indique que cela sera probablement corrigé dans la prochaine version de .NET (quand c'est le cas) mais ce bogue rend notre application fondamentalement inutilisable maintenant.
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: Nous avons également essayé de supprimer simplement les InvalidOperationException
s jetés à l'intérieur de notre base ViewModel événement PropertyChanged de classe. Cela semblait réduire un peu le nombre d'exceptions, mais maintenant nous les frappons juste dans CollectionChanged
événement.
Avez-vous essayé d'augmenter OnPropertyChanged dans votre code avec une priorité différente en utilisant Dispatcher.Invoke - si possible? C'est parfois quelque chose que j'utilise pour influencer - un peu au hasard je suis d'accord :-) WPF sur les conditions de course ... –
Une conjecture sauvage, mais pourriez-vous geler toutes les ressources de brosse référencées dans le dictionnaire lors de leur instanciation? Vous pouvez lire comment le faire ici: http://stackoverflow.com/questions/799890/how-can-wpf-objects-deriving-from-freezable-be-frozen-in-xaml –
Aussi, avez-vous fait en sorte que vous modifiez uniquement ObservableCollection à partir du thread d'interface utilisateur? –