diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs index 65fa6f3e8b..e88199cdad 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs @@ -313,33 +313,51 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions if (itemType is not null && types.AvaloniaList.MakeGenericType(itemType).IsAssignableFrom(type)) { - const StringSplitOptions trimOption = (StringSplitOptions)2; // StringSplitOptions.TrimEntries - var separators = new[] { "," }; - var splitOptions = StringSplitOptions.RemoveEmptyEntries | trimOption; - - var attribute = type.CustomAttributes.FirstOrDefault(a => a.Type == types.AvaloniaListAttribute); - if (attribute is not null) + string[] items; + // Normalize special case of Points collection. + if (itemType == types.Point) { - if (attribute.Properties.TryGetValue("Separators", out var separatorsArray)) + var pointParts = text.Split(new[] { ",", " " }, StringSplitOptions.RemoveEmptyEntries); + if (pointParts.Length % 2 == 0) { - separators = ((Array)separatorsArray)?.OfType().ToArray(); + items = new string[pointParts.Length / 2]; + for (int i = 0; i < pointParts.Length; i += 2) + { + items[i / 2] = string.Format(CultureInfo.InvariantCulture, "{0} {1}", pointParts[i], + pointParts[i + 1]); + } } - if (attribute.Properties.TryGetValue("SplitOptions", out var splitOptionsObj)) + else { - splitOptions = (StringSplitOptions)splitOptionsObj; + throw new XamlX.XamlLoadException($"Invalid PointsList.", node); } } - - var items = text.Split(separators, splitOptions ^ trimOption); - // Compiler targets netstandard, so we need to emulate StringSplitOptions.TrimEntries, if it was requested. - if (splitOptions.HasFlag(trimOption)) + else { - items = items.Select(i => i.Trim()).ToArray(); - } + const StringSplitOptions trimOption = (StringSplitOptions)2; // StringSplitOptions.TrimEntries + var separators = new[] { "," }; + var splitOptions = StringSplitOptions.RemoveEmptyEntries | trimOption; - if (itemType is null) - { - throw new XamlX.XamlLoadException($"Type '{type.Name}' is not a collection type.", node); + var attribute = type.CustomAttributes.FirstOrDefault(a => a.Type == types.AvaloniaListAttribute); + if (attribute is not null) + { + if (attribute.Properties.TryGetValue("Separators", out var separatorsArray)) + { + separators = ((Array)separatorsArray)?.OfType().ToArray(); + } + + if (attribute.Properties.TryGetValue("SplitOptions", out var splitOptionsObj)) + { + splitOptions = (StringSplitOptions)splitOptionsObj; + } + } + + items = text.Split(separators, splitOptions ^ trimOption); + // Compiler targets netstandard, so we need to emulate StringSplitOptions.TrimEntries, if it was requested. + if (splitOptions.HasFlag(trimOption)) + { + items = items.Select(i => i.Trim()).ToArray(); + } } var nodes = new IXamlAstValueNode[items.Length]; diff --git a/tests/Avalonia.RenderTests/Shapes/PolygonTests.cs b/tests/Avalonia.RenderTests/Shapes/PolygonTests.cs index 3ac884df7d..b918f7180a 100644 --- a/tests/Avalonia.RenderTests/Shapes/PolygonTests.cs +++ b/tests/Avalonia.RenderTests/Shapes/PolygonTests.cs @@ -30,7 +30,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes Stroke = Brushes.DarkBlue, Stretch = Stretch.Uniform, Fill = Brushes.Violet, - Points = new [] { new Point(5, 0), new Point(8, 8), new Point(0, 3), new Point(10, 3), new Point(2, 8) }, + Points = new Points { new Point(5, 0), new Point(8, 8), new Point(0, 3), new Point(10, 3), new Point(2, 8) }, StrokeThickness = 1 } }; @@ -52,7 +52,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes Stroke = Brushes.DarkBlue, Stretch = Stretch.Fill, Fill = Brushes.Violet, - Points = new[] { new Point(5, 0), new Point(8, 8), new Point(0, 3), new Point(10, 3), new Point(2, 8) }, + Points = new Points { new Point(5, 0), new Point(8, 8), new Point(0, 3), new Point(10, 3), new Point(2, 8) }, StrokeThickness = 5, } }; diff --git a/tests/Avalonia.RenderTests/Shapes/PolylineTests.cs b/tests/Avalonia.RenderTests/Shapes/PolylineTests.cs index d02d494ff2..12420b524a 100644 --- a/tests/Avalonia.RenderTests/Shapes/PolylineTests.cs +++ b/tests/Avalonia.RenderTests/Shapes/PolylineTests.cs @@ -20,7 +20,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes [Fact] public async Task Polyline_1px_Stroke() { - var polylinePoints = new Point[] { new Point(0, 0), new Point(5, 0), new Point(6, -2), new Point(7, 3), new Point(8, -3), + var polylinePoints = new Points { new Point(0, 0), new Point(5, 0), new Point(6, -2), new Point(7, 3), new Point(8, -3), new Point(9, 1), new Point(10, 0), new Point(15, 0) }; Decorator target = new Decorator @@ -44,7 +44,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes [Fact] public async Task Polyline_10px_Stroke_PenLineJoin() { - var polylinePoints = new Point[] { new Point(0, 0), new Point(5, 0), new Point(6, -2), new Point(7, 3), new Point(8, -3), + var polylinePoints = new Points { new Point(0, 0), new Point(5, 0), new Point(6, -2), new Point(7, 3), new Point(8, -3), new Point(9, 1), new Point(10, 0), new Point(15, 0) }; Decorator target = new Decorator