2011-08-22 9 views
27

저는 최근에 정말 나쁜 WPF 버그를 쳤습니다. Microsoft Connect의 this bug과 같다고 생각합니다. 의 ViewModel가 ItemsControl에에서 이동하는 항목을 일으키는 모든 속성 또는 컬렉션에 변화를 트리거 할 때 2010 년WPF Freezable 버그에 대한 대안?

기본적으로 비주얼 스튜디오를 사용하여

우리의 응용 프로그램을 대상으로 .NET 4.0 클라이언트 프로파일은 예외가 그 기회있다 아래에 던져 질 것입니다. 항상 발생하는 것은 아니며 다른시기에 따라 다른 것으로 나타날 수 있습니다. 신청을 시작한 직후에 더 많은 것으로 보입니다. 예외를 두지 않고 몇 분 동안 사용할 수 있다면 아마 그 응용 프로그램 인스턴스 중에 결코 적중하지 않을 것입니다.

Connect 버그 보고서와 마찬가지로 을 사용하여 ResourceDictionary에서 SolidColorBrush을로드합니다. 사전 중 일부는 수동으로로드됩니다 (지원 대상). 나는 그 사전에있는 모든 것을 수동으로 동결 시키려고했지만, 도움이되지는 않았다.

ObservableCollection에 바인드 된 ItemsControls가있는 기본 창에 두 개 이상의 UserControl을 추가 할 때 예외가 최근에 많이 발생했습니다. 이전에는 50 개 중 1 개 예외 만 보았지만 이제는 5 개 중 4 개가 프로그램을 사용합니다.

해결 방법에 대한 아이디어가 있습니까? Connect 버그는 다음 .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 
    ..... 

편집 : 우리는 단순히 우리의 뷰 모델의 기본 클래스의하여 PropertyChanged 이벤트의 내부에 던져 어떤 InvalidOperationException의 억제 시도했습니다. 이는 예외 수를 다소 줄이는 것처럼 보였지만 이제는 ObservableCollectionCollectionChanged 이벤트에 도달했습니다.

+0

Dispatcher.Invoke를 사용하여 다른 우선 순위로 코드에서 OnPropertyChanged를 발생 시키려고 했습니까? 때로는 영향을주기 위해 사용하는 것입니다 - 조금은 무작위로 동의합니다 :-) 경쟁 조건에 대한 WPF ... –

+2

야생 추측이지만 인스턴스 생성시 사전에 참조 된 브러시 리소스를 모두 고정 할 수 있습니까? 여기에서하는 방법을 읽을 수 있습니다 : http://stackoverflow.com/questions/799890/how-can-wpf-objects-deriving-from-freezable-be-frozen-in-xaml –

+0

또한, UI 스레드에서 ObservableCollection 만 수정하면됩니까? –

답변

20

이 .net 버그를 해결하려면 코드에서 솔리드 컬러 브러시를 모두 고정시켜 고정하십시오.자세한 내용은 여기를 참조 자세한 내용은

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

: 예를 들어

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

을 변경해야 How can WPF objects deriving from Freezable be frozen in XAML?합니다.

+0

이 문제가 해결 된 것 같습니다! 사전을로드 할 때 내 설명서가 완전히 작동하지 않는 것 같아요. –

+0

굉장해! 얼마나 단순한가, 완전히 나를 도왔다. –

+2

나는 "po"가 무엇인지 궁금합니다. – tofutim

0

ItemsControl 및 파생 컨트롤을 사용하여 MVVM과 관련된 버그가 발생할 때마다 VirtualizingStackPanel을 비활성화하는 것이 좋습니다.

<ItemsControl VirtualizingStackPanel.IsVirtualizing="False" /> 

그냥 시도

...

+1

나는 이것을 시도하고 응용 프로그램의 모든 ComboBox/ItemsControl/ListBox에 설정했습니다. 차이를 만드는 것 같지 않습니다. –

3

나는 생각하지 않는다는 이것에 대한 해결 방법이 있습니다. 이 글을 읽으면서 WPF는 리소스를 자동으로 고정시킵니다. 따라서 언제든지 해당 리소스에서 DynamicResource를 사용하려고하면 freezable 예외가 발생합니다. '스타일 및 템플릿은 여러 스레드에서 사용할 수 있습니다

"WPF 스타일이나 템플릿 내부에 freezables을 동결하고, freezables을 수행 할 수 있습니다. 여기

무슨 일이 일어나고에서 Microsoft 재단 팀에서 인용 한 것입니다 우리가 현재 고정되어 있지 않다면. 우리는 현재 응용 프로그램 리소스 내에 을 넣는 것을 고려 중입니다. 동결 된 freezable 때문에 동결 된 freezable의 DynamicResource가 작동하지 않습니다. 잠재적으로 여러 개의 부모가 있습니다. 그래서 모호합니다. 부모는 우리가 r을 검색 할 것입니다. esource. "

+0

'DynamicResource'는 고정 된'Freezable'에서 참조가 작동합니다 - 응용 프로그램이 시작되어 많은 시간 동안 잘 작동합니다. 참조하고있는 리소스는 브러시와 같이 동적 또는 정적 리소스 조회가없는 브러시와 같습니다. 그들은 모두 다음과 같이 보입니다 : ' 또한, WPF는 사전이로드 될 때 자동으로 즉시 고정하지 않는 것 같습니다. 그래서 내가 그들을 수동으로 얼입니다. –