Подтвердить что ты не робот

Обходной путь для WPF Freezable ошибка?

Недавно я столкнулся с очень плохой ошибкой WPF. Я думаю, что это так же, как эта ошибка в Microsoft Connect.

Наше приложение нацелено на профиль клиента .NET 4.0 с помощью Visual Studio 2010.

В принципе, когда ViewModel запускает изменение любого свойства или коллекции, которое заставляет элементы перемещаться в ItemsControl, есть вероятность, что будет выбрано исключение. Это не всегда происходит и, похоже, происходит в зависимости от разных триггеров в разное время. Скорее всего, вскоре после запуска приложения. Если вы можете использовать его в течение пары минут, не попав в исключение, вы, вероятно, никогда не будете бить во время этого экземпляра приложения.

Как и отчет об ошибке подключения, я использую {DynamicResource key} для загрузки SolidColorBrush es из ResourceDictionary. Некоторые словари загружаются вручную (для поддержки поддержки). Я попытался вручную заморозить все в этих словарях, но, похоже, это не помогло.

В последнее время исключения стали гораздо более частыми, когда я добавил еще пару UserControl в главное окно, в которых элементы ItemsControls привязаны к ObservableCollection s. Раньше я видел только исключение 1 раз из 50, но теперь я вижу это 4 из 5 раз, я использую программу.

Есть ли у кого-нибудь идеи для обходных решений? Ошибка подключения указывает, что это, вероятно, будет исправлено в следующей версии .NET(если есть), но эта ошибка делает наше приложение в настоящее время непригодным для использования.

    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: Мы также попробовали просто подавить любой InvalidOperationException, который был заброшен внутри нашего объекта PropertyChanged в базовом классе ViewModel. Это несколько уменьшило количество исключений, но теперь мы просто ударили их в событие ObservableCollection CollectionChanged.

4b9b3361

Ответ 1

Чтобы обойти эту ошибку .net, измените все сплошные цветные кисти в вашем коде, чтобы их можно было заморозить. Например

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

следует изменить на:

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

Более подробные инструкции см. здесь: Как можно заморозить объекты WPF из Freezable в XAML?.

Ответ 2

Я не верю, что для этого есть обход. Имея дело с этим сам, из того, что я читал, WPF автоматически замораживает ресурсы при создании. Поэтому в любое время, когда вы пытаетесь использовать DynamicResource на этом ресурсе, вы получите исключение для замораживания.

Вот цитата из команды Microsoft Foundation о том, что происходит:

"WPF заморозит любые freezables внутри стиля или шаблона. Стили и шаблоны могут использоваться на нескольких потоках, а freezables не может, кроме они заморожены. В настоящее время мы планируем распространить это на любой внутри Application.Resources, так как это имеет ту же проблему с потоками... DynamicResource на замороженном замораживании не работает, поскольку у замороженного замораживания потенциально есть несколько родителей - так что это двусмысленно, родительский, мы будем искать ресурс ".

Ответ 3

Каждый раз, когда речь идет о неправильном поведении вокруг MVVM с помощью ItemsControl и производных элементов управления, первая попытка - отключить VirtualizingStackPanel.

<ItemsControl VirtualizingStackPanel.IsVirtualizing="False" />

Просто попробуйте...