Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 53 additions & 10 deletions src/Controls/src/SourceGen/TypeConverters/ThicknessConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,36 +26,79 @@ public string Convert(string value, BaseNode node, ITypeSymbol toType, IndentedT
switch (thickness.Length)
{
case 2:
if (double.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out double h)
&& double.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out double v))
if (TryParseDouble(thickness[0], out double h)
&& TryParseDouble(thickness[1], out double v))
{
var thicknessType = context.Compilation.GetTypeByMetadataName("Microsoft.Maui.Thickness")!;
return $"new {thicknessType.ToFQDisplayString()}({FormatInvariant(h)}, {FormatInvariant(v)})";
return $"new {thicknessType.ToFQDisplayString()}({FormatDouble(h)}, {FormatDouble(v)})";
}
break;
case 4:
if (double.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out double l)
&& double.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out double t)
&& double.TryParse(thickness[2], NumberStyles.Number, CultureInfo.InvariantCulture, out double r)
&& double.TryParse(thickness[3], NumberStyles.Number, CultureInfo.InvariantCulture, out double b))
if (TryParseDouble(thickness[0], out double l)
&& TryParseDouble(thickness[1], out double t)
&& TryParseDouble(thickness[2], out double r)
&& TryParseDouble(thickness[3], out double b))
{
var thicknessType = context.Compilation.GetTypeByMetadataName("Microsoft.Maui.Thickness")!;
return $"new {thicknessType.ToFQDisplayString()}({FormatInvariant(l)}, {FormatInvariant(t)}, {FormatInvariant(r)}, {FormatInvariant(b)})";
return $"new {thicknessType.ToFQDisplayString()}({FormatDouble(l)}, {FormatDouble(t)}, {FormatDouble(r)}, {FormatDouble(b)})";
}
break;
}
}
else
{ //single uniform thickness
if (double.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out double l))
if (TryParseDouble(value, out double l))
{
var thicknessType = context.Compilation.GetTypeByMetadataName("Microsoft.Maui.Thickness")!;
return $"new {thicknessType.ToFQDisplayString()}({FormatInvariant(l)})";
return $"new {thicknessType.ToFQDisplayString()}({FormatDouble(l)})";
}
}
}

context.ReportConversionFailed(xmlLineInfo, value, Descriptors.ThicknessConversionFailed);
return "default";
}

/// <summary>
/// Tries to parse a double value, including special values like NaN, Infinity, -Infinity.
/// </summary>
static bool TryParseDouble(string value, out double result)
{
value = value.Trim();

// Handle special values that NumberStyles.Number doesn't parse
if (value.Equals("NaN", System.StringComparison.OrdinalIgnoreCase))
{
result = double.NaN;
return true;
}
if (value.Equals("Infinity", System.StringComparison.OrdinalIgnoreCase) ||
value.Equals("+Infinity", System.StringComparison.OrdinalIgnoreCase))
{
result = double.PositiveInfinity;
return true;
}
if (value.Equals("-Infinity", System.StringComparison.OrdinalIgnoreCase))
{
result = double.NegativeInfinity;
return true;
}

return double.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out result);
}

/// <summary>
/// Formats a double value for C# code generation, handling special values.
/// </summary>
static string FormatDouble(double value)
{
if (double.IsNaN(value))
return "double.NaN";
if (double.IsPositiveInfinity(value))
return "double.PositiveInfinity";
if (double.IsNegativeInfinity(value))
return "double.NegativeInfinity";

return FormatInvariant(value);
}
}
7 changes: 7 additions & 0 deletions src/Controls/tests/Xaml.UnitTests/Issues/Maui33871.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Microsoft.Maui.Controls.Xaml.UnitTests.Maui33871">
<!-- Test: Thickness type converter should handle NaN values -->
<Button x:Name="nanButton" Text="NaN Padding" Padding="NaN"/>
</ContentPage>
30 changes: 30 additions & 0 deletions src/Controls/tests/Xaml.UnitTests/Issues/Maui33871.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Xunit;

namespace Microsoft.Maui.Controls.Xaml.UnitTests;

public partial class Maui33871 : ContentPage
{
public Maui33871() => InitializeComponent();

[Collection("Issue")]
public class Tests
{
[Theory]
[XamlInflatorData]
internal void ThicknessConverterHandlesNaN(XamlInflator inflator)
{
// This test reproduces issue #33871:
// XSG fails to parse Padding="NaN" which creates a Thickness with all NaN values.
// This is used by Button to indicate "use platform default padding".
var page = new Maui33871(inflator);

Assert.NotNull(page);
Assert.NotNull(page.nanButton);

// Verify the padding was parsed correctly as NaN
Assert.True(page.nanButton.Padding.IsNaN);
}
}
}
Loading