Forum Xamarin.iOS

"Collection was modified" when updating dynamic resources

AlexanderMelchersAlexanderMelchers NLMember ✭✭

Hi all,

So here's the background: to support accessibility, we'd like to make our app responsive to text size changes set in the system preferences. We don't like to use named font-sizes, as there's too much difference between the styles used on Android and iOS, which would affect the look of our app. The solution we came up with is to define our own "named font sizes" - i.e. application-level resources of type Double that are then applied throughout the app as dynamic resources. When then use the same the technique Xamarin Forms uses internally to determine a scale factor: always 1 for Android (this OS solves the issue itself, and the scale factor vis-à-vis the current preferred body size on iOS (i.e. UIFont.PreferredBody.PointSize / 17). With that, we update the aforementioned resources, and the result is our app can respond to dynamic font sizing.

This all works a charm on Android, as it does on iOS when running the scaling in the App's constructor. However, to make our app more responsive and dynamically apply these changes when the app is resumed, we'd like to call the same font scaling code OnResume. This is where the problems start.

When we try to update the dynamic resource font sizes OnResume, the app crashes with a System.InvalidOperationException "Collection was modified; enumeration operation may not execute." This only happens on iOS, only on iOS 13, only OnResume, and only for certain resources (these resources are on the page being shown, but other resources on the same page do not experience the issue). The exception occurs when trying the following line of code:

Current.Resources[fontName] = storedFontSize * scalingFactor;

What seems to happen is that this dynamic resource change triggers further changes to other resources, which cause the resource-collection being updated to change, so that any subsequent (or is that concurrent??!?) updates to the same resource-collection will fail.

Seeing as our code is proprietary, I can't share, unfortunately, but: any ideas?

Thanks for your help!

Answers

  • AlexanderMelchersAlexanderMelchers NLMember ✭✭

    In case this is of any help, here's a stack trace:

    {System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
      at System.Collections.Generic.List`1+Enumerator[T].MoveNextRare () [0x00013] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corefx/src/Common/src/CoreLib/System/Collections/Generic/List.cs:1163 
      at System.Collections.Generic.List`1+Enumerator[T].MoveNext () [0x0004a] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corefx/src/Common/src/CoreLib/System/Collections/Generic/List.cs:1156 
      at Xamarin.Forms.Element.OnResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x0002d] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:420 
      at Xamarin.Forms.Element.OnParentResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:398 
      at Xamarin.Forms.VisualElement.OnParentResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00019] in D:\a\1\s\Xamarin.Forms.Core\VisualElement.cs:907 
      at Xamarin.Forms.Element.OnParentResourcesChanged (System.Object sender, Xamarin.Forms.Internals.ResourcesChangedEventArgs e) [0x0000f] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:393 
      at Xamarin.Forms.Element.OnResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00021] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:421 
      at Xamarin.Forms.Element.OnParentResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:398 
      at Xamarin.Forms.VisualElement.OnParentResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00019] in D:\a\1\s\Xamarin.Forms.Core\VisualElement.cs:907 
      at Xamarin.Forms.Element.OnParentResourcesChanged (System.Object sender, Xamarin.Forms.Internals.ResourcesChangedEventArgs e) [0x0000f] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:393 
      at Xamarin.Forms.Element.OnResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00021] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:421 
      at Xamarin.Forms.Element.OnParentResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:398 
      at Xamarin.Forms.VisualElement.OnParentResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00019] in D:\a\1\s\Xamarin.Forms.Core\VisualElement.cs:907 
      at Xamarin.Forms.Element.OnParentResourcesChanged (System.Object sender, Xamarin.Forms.Internals.ResourcesChangedEventArgs e) [0x0000f] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:393 
      at Xamarin.Forms.Element.OnResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00021] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:421 
      at Xamarin.Forms.Element.OnParentResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:398 
      at Xamarin.Forms.VisualElement.OnParentResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00019] in D:\a\1\s\Xamarin.Forms.Core\VisualElement.cs:907 
      at Xamarin.Forms.Element.OnParentResourcesChanged (System.Object sender, Xamarin.Forms.Internals.ResourcesChangedEventArgs e) [0x0000f] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:393 
      at Xamarin.Forms.Element.OnResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00021] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:421 
      at Xamarin.Forms.Element.OnParentResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:398 
      at Xamarin.Forms.VisualElement.OnParentResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00019] in D:\a\1\s\Xamarin.Forms.Core\VisualElement.cs:907 
      at Xamarin.Forms.Element.OnParentResourcesChanged (System.Object sender, Xamarin.Forms.Internals.ResourcesChangedEventArgs e) [0x0000f] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:393 
      at Xamarin.Forms.Element.OnResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00021] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:421 
      at Xamarin.Forms.Element.OnParentResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:398 
      at Xamarin.Forms.VisualElement.OnParentResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00019] in D:\a\1\s\Xamarin.Forms.Core\VisualElement.cs:907 
      at Xamarin.Forms.Element.OnParentResourcesChanged (System.Object sender, Xamarin.Forms.Internals.ResourcesChangedEventArgs e) [0x0000f] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:393 
      at Xamarin.Forms.Element.OnResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00021] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:421 
      at Xamarin.Forms.Element.OnParentResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:398 
      at Xamarin.Forms.VisualElement.OnParentResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00019] in D:\a\1\s\Xamarin.Forms.Core\VisualElement.cs:907 
      at Xamarin.Forms.Element.OnParentResourcesChanged (System.Object sender, Xamarin.Forms.Internals.ResourcesChangedEventArgs e) [0x0000f] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:393 
      at Xamarin.Forms.Element.OnResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00021] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:421 
      at Xamarin.Forms.Element.OnParentResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:398 
      at Xamarin.Forms.VisualElement.OnParentResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00019] in D:\a\1\s\Xamarin.Forms.Core\VisualElement.cs:907 
      at Xamarin.Forms.Element.OnParentResourcesChanged (System.Object sender, Xamarin.Forms.Internals.ResourcesChangedEventArgs e) [0x0000f] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:393 
      at Xamarin.Forms.Element.OnResourcesChanged (System.Collections.Generic.IEnumerable`1[T] values) [0x00021] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:421 
      at Xamarin.Forms.Element.OnResourcesChanged (System.Object sender, Xamarin.Forms.Internals.ResourcesChangedEventArgs e) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:412 
      at Xamarin.Forms.ResourceDictionary.OnValuesChanged (System.Collections.Generic.KeyValuePair`2[System.String,System.Object][] values) [0x00008] in D:\a\1\s\Xamarin.Forms.Core\ResourceDictionary.cs:327 
      at Xamarin.Forms.ResourceDictionary.OnValueChanged (System.String key, System.Object value) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\ResourceDictionary.cs:320 
      at Xamarin.Forms.ResourceDictionary.set_Item (System.String index, System.Object value) [0x0000d] in D:\a\1\s\Xamarin.Forms.Core\ResourceDictionary.cs:213 
      at OurApp.App.<RescaleFontSizes>b__12_0 (System.Collections.Generic.KeyValuePair`2[TKey,TValue] fontSize) [0x00002] in C:\TFS\OurApp-Next\src\OurApp\App.xaml.cs:159 }
    
Sign In or Register to comment.