[BUG] MathExpressionConverter doesn't support negative numbers when in Arabic (ar_AR)
Is there an existing issue for this?
- [x] I have searched the existing issues
Did you read the "Reporting a bug" section on Contributing file?
- [x] I have read the "Reporting a bug" section on Contributing file: https://github.com/CommunityToolkit/Maui/blob/main/CONTRIBUTING.md#reporting-a-bug
Current Behavior
When your CultureInfo.CurrentCulture = new CultureInfo("ar-AR") the MathExpressionConverter will raise an exception when the expression contains negative numbers (e.g. x0 ? -90 : 90):
HResult: -2146233033 (0x80131537) Message: The input string '-90' was not in a correct format.
Here's the call stack:
at System.Number.ThrowFormatException[TChar](ReadOnlySpan1 value) at System.Double.Parse(String s) at CommunityToolkit.Maui.Converters.MathExpression.ParsePrimary() in /_/src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpression.shared.cs:line 365 at CommunityToolkit.Maui.Converters.MathExpression.ParseBinaryOperators(Regex BinaryOperators, Func1 ParseNext) in //src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpression.shared.cs:line 337
at CommunityToolkit.Maui.Converters.MathExpression.ParsePower() in //src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpression.shared.cs:line 333
at CommunityToolkit.Maui.Converters.MathExpression.ParseBinaryOperators(Regex BinaryOperators, Func1 ParseNext) in /_/src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpression.shared.cs:line 337 at CommunityToolkit.Maui.Converters.MathExpression.ParseProduct() in /_/src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpression.shared.cs:line 331 at CommunityToolkit.Maui.Converters.MathExpression.ParseBinaryOperators(Regex BinaryOperators, Func1 ParseNext) in //src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpression.shared.cs:line 337
at CommunityToolkit.Maui.Converters.MathExpression.ParseSum() in //src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpression.shared.cs:line 329
at CommunityToolkit.Maui.Converters.MathExpression.ParseBinaryOperators(Regex BinaryOperators, Func1 ParseNext) in /_/src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpression.shared.cs:line 337 at CommunityToolkit.Maui.Converters.MathExpression.ParseCompare() in /_/src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpression.shared.cs:line 327 at CommunityToolkit.Maui.Converters.MathExpression.ParseBinaryOperators(Regex BinaryOperators, Func1 ParseNext) in //src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpression.shared.cs:line 357
at CommunityToolkit.Maui.Converters.MathExpression.ParseEquality() in //src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpression.shared.cs:line 325
at CommunityToolkit.Maui.Converters.MathExpression.ParseBinaryOperators(Regex BinaryOperators, Func1 ParseNext) in /_/src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpression.shared.cs:line 337 at CommunityToolkit.Maui.Converters.MathExpression.ParseLogicalAnd() in /_/src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpression.shared.cs:line 323 at CommunityToolkit.Maui.Converters.MathExpression.ParseBinaryOperators(Regex BinaryOperators, Func1 ParseNext) in //src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpression.shared.cs:line 337
at CommunityToolkit.Maui.Converters.MathExpression.ParseLogicalOR() in //src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpression.shared.cs:line 321
at CommunityToolkit.Maui.Converters.MathExpression.ParseConditional() in //src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpression.shared.cs:line 302
at CommunityToolkit.Maui.Converters.MathExpression.ParseExpr() in //src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpression.shared.cs:line 287
at CommunityToolkit.Maui.Converters.MathExpression.ParseExpression() in //src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpression.shared.cs:line 282
at CommunityToolkit.Maui.Converters.MathExpression.CalculateResult() in //src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpression.shared.cs:line 128
at CommunityToolkit.Maui.Converters.MathExpressionConverter.ConvertFrom(Object inputValue, String parameter, CultureInfo culture) in //src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpressionConverter.shared.cs:line 25
at CommunityToolkit.Maui.Converters.BaseConverter`3.CommunityToolkit.Maui.Converters.ICommunityToolkitValueConverter.Convert(Object value, Type targetType, Object parameter, CultureInfo culture) in //src/CommunityToolkit.Maui/Converters/BaseConverter.shared.cs:line 91
at CommunityToolkit.Maui.Converters.ICommunityToolkitValueConverter.Microsoft.Maui.Controls.IValueConverter.Convert(Object value, Type targetType, Object parameter, CultureInfo culture) in /_/src/CommunityToolkit.Maui/Converters/ICommunityToolkitValueConverter.shared.cs:line 57
at Microsoft.Maui.Controls.Binding.GetSourceValue(Object value, Type targetPropertyType)
at Microsoft.Maui.Controls.BindingExpression.ApplyCore(Object sourceObject, BindableObject target, BindableProperty property, Boolean fromTarget, SetterSpecificity specificity)
at Microsoft.Maui.Controls.BindingExpression.Apply(Boolean fromTarget)
at Microsoft.Maui.Controls.BindingExpression.BindingExpressionPart.<PropertyChanged>b__50_0()
at Microsoft.Maui.Controls.DispatcherExtensions.DispatchIfRequired(IDispatcher dispatcher, Action action)
at Microsoft.Maui.Controls.BindingExpression.BindingExpressionPart.PropertyChanged(Object sender, PropertyChangedEventArgs args)
at Microsoft.Maui.Controls.BindingExpression.WeakPropertyChangedProxy.OnPropertyChanged(Object sender, PropertyChangedEventArgs e)
at Microsoft.Maui.Controls.BindableObject.OnPropertyChanged(String propertyName)
at Microsoft.Maui.Controls.Element.OnPropertyChanged(String propertyName)
at Microsoft.Maui.Controls.BindableObject.OnBindablePropertySet(BindableProperty property, Object original, Object value, Boolean didChange, Boolean willFirePropertyChanged)
at Microsoft.Maui.Controls.Element.OnBindablePropertySet(BindableProperty property, Object original, Object value, Boolean changed, Boolean willFirePropertyChanged)
at Microsoft.Maui.Controls.BindableObject.SetValueActual(BindableProperty property, BindablePropertyContext context, Object value, Boolean currentlyApplying, SetValueFlags attributes, SetterSpecificity specificity, Boolean silent)
at Microsoft.Maui.Controls.BindableObject.SetValueCore(BindableProperty property, Object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes, SetterSpecificity specificity)
at Microsoft.Maui.Controls.BindableObject.SetValue(BindableProperty property, Object value, SetterSpecificity specificity)
at Microsoft.Maui.Controls.CheckBox.Microsoft.Maui.ICheckBox.set_IsChecked(Boolean value)
at Microsoft.Maui.Handlers.CheckBoxHandler.OnChecked(Object sender, RoutedEventArgs e)
at WinRT._EventSource_global__Microsoft_UI_Xaml_RoutedEventHandler.EventState.<GetEventInvoke>b__1_0(Object sender, RoutedEventArgs e)
at ABI.Microsoft.UI.Xaml.RoutedEventHandler.Do_Abi_Invoke(IntPtr thisPtr, IntPtr sender, IntPtr e)
Expected Behavior
The MathExpressionConverter should be able to handle expressions with negative numbers without encountering exceptions.
Steps To Reproduce
The following is a XAML minimal repro case
<VerticalStackLayout Padding="30,0" Spacing="25">
<Label Text="Click on the CheckBox below and observe the corresponding Label changing its orientation. When set to Arabic, however, clicking on the CheckBox will crash the app." />
<CheckBox x:Name="ExpandedCheck" IsChecked="True" />
<Label
HorizontalOptions="Start"
Rotation="{Binding IsChecked,
Source={Reference ExpandedCheck},
x:DataType=CheckBox,
Converter={StaticResource MathExpressionConverter},
ConverterParameter='x0 ? -90 : 90'}"
Text=">" />
</VerticalStackLayout>
Link to public reproduction project repository
https://github.com/stephenquan/MauiMCTMinusBug
Environment
- .NET MAUI CommunityToolkit: 12.0
- OS: Windows 11
- .NET MAUI: 9.0.70
Anything else?
I believe the bug is on the following offending line: https://github.com/CommunityToolkit/Maui/blob/ecc51ed31434b09c6e32003149d10c13023af6f2/src/CommunityToolkit.Maui/Converters/MathExpressionConverter/MathExpression.shared.cs#L365
I am just curious what is the expected format for Arabic? 09-
I think the parser should use InvariantCulture when parsing numeric values in mathematical expressions.
I was having a related problem where my expression was x*0.5 where it would multiply by 5 when the culture is German and divide by 2 when the culture is English. My application is bilingual (German and English) and German uses . as the thousands separator and , as the decimal separator unlike English. I worked around my problem by using x/2 as the expression.
I was thinking of creating a new issue but when I found this issue I think it is related, so I don't think I should create a new issue.
In my opinion, I don't see a case where the developer intends to use a culture specific number in the expression. Typically culture formatted values are intended only when the value is displayed to the user. Since the expression for the MathExpressionConverter is not intended for the user, it's safe to assume that InvariantCulture is the always the intent. The mathematical expression should be treated like expressions in C# code where the culture is always invariant.
However, fixing it may cause breaking changes if a developer depended on the buggy (in my opinion) behavior.
I am just curious what is the expected format for Arabic? 09-
The expected format is "\u061c-90" where the Unicode character '\u0615' is ARABIC LETTER MARK which is used by the Bidirectional Algorithm to display text when there is mixed left to right and right to left characters in the text.