Browse Source

Fix XML child-value syntax in Setters (#16153)

Max Katz 1 year ago
parent
commit
2935763c25

+ 24 - 9
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs

@@ -82,17 +82,32 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
             }
 
             var valueProperty = on.Children
-                .OfType<XamlAstXamlPropertyValueNode>().FirstOrDefault(p => p.Property.GetClrProperty().Name == "Value");
-            if (valueProperty?.Values?.Count == 1 && valueProperty.Values[0] is XamlAstTextNode)
+                .OfType<XamlAstXamlPropertyValueNode>()
+                .FirstOrDefault(p => p.Property.GetClrProperty().Name == "Value" && p.Values.Count == 1 && p.Values[0] is XamlAstTextNode);
+            var textValue = valueProperty?.Values.FirstOrDefault() as XamlAstTextNode
+                            ?? on.Children.OfType<XamlAstTextNode>().FirstOrDefault();
+            if (textValue is not null
+                && XamlTransformHelpers.TryGetCorrectlyTypedValue(context, textValue,
+                    propType, out _))
             {
-                if (!XamlTransformHelpers.TryGetCorrectlyTypedValue(context, valueProperty.Values[0],
-                        propType, out var converted))
-                    throw new XamlStyleTransformException(
-                        $"Unable to convert property value to {propType.GetFqn()}",
-                        valueProperty.Values[0]);
-
-                valueProperty.Property = new SetterValueProperty(valueProperty.Property,
+                
+                var setterValueProperty = new SetterValueProperty(
+                    (IXamlLineInfo)valueProperty?.Property ?? textValue,
                     on.Type.GetClrType(), propType, avaloniaTypes);
+                if (valueProperty is not null)
+                {
+                    valueProperty.Property = setterValueProperty;
+                }
+                else
+                {
+                    on.Children[on.Children.IndexOf(textValue)] =
+                        new XamlAstXamlPropertyValueNode(textValue, setterValueProperty, textValue, false);
+                }
+            }
+            // If we have `Value` property with plain text content that wasn't parsed, throw an exception.
+            else if (valueProperty is not null && textValue is not null)
+            {
+                throw new XamlStyleTransformException($"Unable to convert property value to {propType.GetFqn()}", textValue);
             }
 
             // Handling a very specific case, when ITemplate value is used inside of Setter.Value,

+ 18 - 0
tests/Avalonia.Markup.Xaml.UnitTests/StyleTests.cs

@@ -24,6 +24,24 @@ namespace Avalonia.Markup.Xaml.UnitTests
             }
         }
 
+        [Fact]
+        public void Xml_Value_Should_Be_Assigned_To_Setter_Value()
+        {
+            using (UnitTestApplication.Start(TestServices.MockPlatformWrapper))
+            {
+                var style = (Style)AvaloniaRuntimeXamlLoader.Load(@"
+<Style Selector='Button' xmlns='https://github.com/avaloniaui'>
+    <Setter Property='Margin'>
+        10, 4, 0, 4
+    </Setter>
+</Style>");
+                var setter = (Setter)(style.Setters.First());
+
+                var thickness = Assert.IsType<Thickness>(setter.Value);
+                Assert.Equal(new Thickness(10, 4, 0, 4), thickness);
+            }
+        }
+        
         [Fact]
         public void Setter_With_TwoWay_Binding_Should_Update_Source()
         {