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
In case this is of any help, here's a stack trace:
I'm having this exact issue and can't for the life of me figure out what's wrong, did you manage to find a resolution?
Ta
Unfortunately, we didn't. As in our use-case proper updating was desirable, but not critical, we ended up just putting a try-catch around each of the updates, thus skipping those that would fail and keeping those that didn't. In our case this means that for the user to receive a properly updated UI, they'll need to restart the app.