lilcodelab / Xamarin.Plugin.Calendar

Calendar plugin for Xamarin.Forms
MIT License
260 stars 61 forks source link

[Bug] Crash with some Cultures because of abbreviated day name length #64

Closed inimirpaz closed 3 years ago

inimirpaz commented 4 years ago

Describe the bug The app crashes when the plugin Calendar is used with Cultures whose AbbreviatedDayNames are not all the same length, DaysTitleMaximumLength is not explicitly set, and the shortest name has a char count lower than 3 characters (e.g. Hungarian, Belarusian, Maori, ...), resulting in

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentOutOfRangeException: Index and length must refer to a location within the string.

To Reproduce Steps to reproduce the behavior:

  1. Bind the Culture of the Calendar control to a variable set to -for instance- Hungarian (hu).
  2. Do not set the DaysTitleMaximumLength property (defaults to 3), or set it to 2.

Expected behavior The app should not crash and the calendar should show the day names up to the min between DaysTitleMaximumLength and the day name length itself.

Version information:

Additional context The culprit of the crash is located at this very line of code as of the complete stacktrace:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentOutOfRangeException: Index and length must refer to a location within the string.
Parameter name: length
  at System.String.Substring (System.Int32 startIndex, System.Int32 length) [0x0004c] in <5e301229c46f4675aa8af93f827c14a9>:0 
  at Xamarin.Plugin.Calendar.Controls.MonthDaysView.UpdateDayTitles () [0x0004d] in <11a4cfdcbc214d80a40fff879666004e>:0 
  at Xamarin.Plugin.Calendar.Controls.MonthDaysView.OnPropertyChanged (System.String propertyName) [0x00294] in <11a4cfdcbc214d80a40fff879666004e>:0 
  at Xamarin.Forms.BindableObject.SetValueActual (Xamarin.Forms.BindableProperty property, Xamarin.Forms.BindableObject+BindablePropertyContext context, System.Object value, System.Boolean currentlyApplying, Xamarin.Forms.Internals.SetValueFlags attributes, System.Boolean silent) [0x0011b] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindableObject.SetValueCore (Xamarin.Forms.BindableProperty property, System.Object value, Xamarin.Forms.Internals.SetValueFlags attributes, Xamarin.Forms.BindableObject+SetValuePrivateFlags privateAttributes) [0x00173] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindingExpression.ApplyCore (System.Object sourceObject, Xamarin.Forms.BindableObject target, Xamarin.Forms.BindableProperty property, System.Boolean fromTarget) [0x00214] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindingExpression.Apply (System.Boolean fromTarget) [0x0003e] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindingExpression+BindingExpressionPart.<PropertyChanged>b__49_0 () [0x00000] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindingExpression+BindingExpressionPart.PropertyChanged (System.Object sender, System.ComponentModel.PropertyChangedEventArgs args) [0x000cb] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindingExpression+WeakPropertyChangedProxy.OnPropertyChanged (System.Object sender, System.ComponentModel.PropertyChangedEventArgs e) [0x00012] in <90d760e930d94d67861701555b251ae9>:0 
  at (wrapper delegate-invoke) <Module>.invoke_void_object_PropertyChangedEventArgs(object,System.ComponentModel.PropertyChangedEventArgs)
  at Xamarin.Forms.BindableObject.OnPropertyChanged (System.String propertyName) [0x00012] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.Element.OnPropertyChanged (System.String propertyName) [0x00000] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Plugin.Calendar.Controls.Calendar.OnPropertyChanged (System.String propertyName) [0x00000] in <11a4cfdcbc214d80a40fff879666004e>:0 
  at Xamarin.Forms.BindableObject.SetValueActual (Xamarin.Forms.BindableProperty property, Xamarin.Forms.BindableObject+BindablePropertyContext context, System.Object value, System.Boolean currentlyApplying, Xamarin.Forms.Internals.SetValueFlags attributes, System.Boolean silent) [0x0011b] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindableObject.SetValueCore (Xamarin.Forms.BindableProperty property, System.Object value, Xamarin.Forms.Internals.SetValueFlags attributes, Xamarin.Forms.BindableObject+SetValuePrivateFlags privateAttributes) [0x00173] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindingExpression.ApplyCore (System.Object sourceObject, Xamarin.Forms.BindableObject target, Xamarin.Forms.BindableProperty property, System.Boolean fromTarget) [0x00214] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindingExpression.Apply (System.Object sourceObject, Xamarin.Forms.BindableObject target, Xamarin.Forms.BindableProperty property) [0x0006b] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.Binding.Apply (System.Object context, Xamarin.Forms.BindableObject bindObj, Xamarin.Forms.BindableProperty targetProperty, System.Boolean fromBindingContextChanged) [0x0006d] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindableObject.ApplyBindings (System.Boolean skipBindingContext, System.Boolean fromBindingContextChanged) [0x00049] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindableObject.SetInheritedBindingContext (Xamarin.Forms.BindableObject bindable, System.Object value) [0x0005a] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.Element.SetChildInheritedBindingContext (Xamarin.Forms.Element child, System.Object context) [0x00000] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.TemplatedView.SetChildInheritedBindingContext (Xamarin.Forms.Element child, System.Object context) [0x00008] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.Element.<OnBindingContextChanged>b__82_0 (Xamarin.Forms.BindableObject child, System.Object bc) [0x00000] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindableObjectExtensions.PropagateBindingContext[T] (Xamarin.Forms.BindableObject self, System.Collections.Generic.IList`1[T] children, System.Action`2[T1,T2] setChildBindingContext) [0x0002c] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.Element.OnBindingContextChanged () [0x00007] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.VisualElement.OnBindingContextChanged () [0x00006] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.View.OnBindingContextChanged () [0x0000c] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.ContentView.OnBindingContextChanged () [0x00000] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindableObject.SetInheritedBindingContext (Xamarin.Forms.BindableObject bindable, System.Object value) [0x00062] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.Element.SetChildInheritedBindingContext (Xamarin.Forms.Element child, System.Object context) [0x00000] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.Element.<OnBindingContextChanged>b__82_0 (Xamarin.Forms.BindableObject child, System.Object bc) [0x00000] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindableObjectExtensions.PropagateBindingContext[T] (Xamarin.Forms.BindableObject self, System.Collections.Generic.IList`1[T] children, System.Action`2[T1,T2] setChildBindingContext) [0x0002c] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.Element.OnBindingContextChanged () [0x00007] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.VisualElement.OnBindingContextChanged () [0x00006] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.View.OnBindingContextChanged () [0x0000c] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.Grid.OnBindingContextChanged () [0x00006] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindableObject.SetInheritedBindingContext (Xamarin.Forms.BindableObject bindable, System.Object value) [0x00062] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.Element.SetChildInheritedBindingContext (Xamarin.Forms.Element child, System.Object context) [0x00000] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.TemplatedPage.SetChildInheritedBindingContext (Xamarin.Forms.Element child, System.Object context) [0x00008] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.Element.<OnBindingContextChanged>b__82_0 (Xamarin.Forms.BindableObject child, System.Object bc) [0x00000] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindableObjectExtensions.PropagateBindingContext[T] (Xamarin.Forms.BindableObject self, System.Collections.Generic.IList`1[T] children, System.Action`2[T1,T2] setChildBindingContext) [0x0002c] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.Element.OnBindingContextChanged () [0x00007] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.VisualElement.OnBindingContextChanged () [0x00006] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.Page.OnBindingContextChanged () [0x00000] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.ContentPage.OnBindingContextChanged () [0x00000] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindableObject.BindingContextPropertyChanged (Xamarin.Forms.BindableObject bindable, System.Object oldvalue, System.Object newvalue) [0x0000f] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindableObject.SetValueActual (Xamarin.Forms.BindableProperty property, Xamarin.Forms.BindableObject+BindablePropertyContext context, System.Object value, System.Boolean currentlyApplying, Xamarin.Forms.Internals.SetValueFlags attributes, System.Boolean silent) [0x0012a] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindableObject.SetValueCore (Xamarin.Forms.BindableProperty property, System.Object value, Xamarin.Forms.Internals.SetValueFlags attributes, Xamarin.Forms.BindableObject+SetValuePrivateFlags privateAttributes) [0x00173] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindableObject.SetValue (Xamarin.Forms.BindableProperty property, System.Object value, System.Boolean fromStyle, System.Boolean checkAccess) [0x00042] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindableObject.SetValue (Xamarin.Forms.BindableProperty property, System.Object value) [0x00000] in <90d760e930d94d67861701555b251ae9>:0 
  at Xamarin.Forms.BindableObject.set_BindingContext (System.Object value) [0x00000] in <90d760e930d94d67861701555b251ae9>:0 
  at InimFireApp.Views.CalendarPage.set_ViewModel (InimFireApp.Views.CalendarPage value) [0x00000] in <dde3778d17404487980f1ba1beb75ed0>:0 
  at InimFireApp.Views.CalendarPage..ctor () [0x0009c] in <dde3778d17404487980f1ba1beb75ed0>:0 
  at (wrapper managed-to-native) System.Reflection.RuntimeConstructorInfo.InternalInvoke(System.Reflection.RuntimeConstructorInfo,object,object[],System.Exception&)
  at System.Reflection.RuntimeConstructorInfo.InternalInvoke (System.Object obj, System.Object[] parameters, System.Boolean wrapExceptions) [0x00005] in <5e301229c46f4675aa8af93f827c14a9>:0 

A possible fix could be to change the Substring to

Substring(0, Math.Min((int)DaysTitleMaximumLength), Culture.DateTimeFormat.AbbreviatedDayNames[dayNumber].Length));

Please Note that it may not suffice if the same happens elsewhere in the plugin code.

Workaround

  1. Set DaysTitleMaximumLength to 1 (not always ideal)
  2. Bind the DaysTitleMaximumLength property of the Calendar to a getter field in your ViewModel in which, known your "CurrentCulture" you do the following:
    get
    {
    int dayMaxLength = 3;
    foreach (var day in CurrentCulture.DateTimeFormat.AbbreviatedDayNames)
    {
        if (day.Length < dayMaxLength)
            dayMaxLength = day.Length;
    }
    return (Xamarin.Plugin.Calendar.DaysTitleMaxLength)dayMaxLength;
    }