diff --git a/samples/ControlCatalog/Pages/PlatformInfoPage.xaml b/samples/ControlCatalog/Pages/PlatformInfoPage.xaml index 21255161d6..8eb0dfd8dd 100644 --- a/samples/ControlCatalog/Pages/PlatformInfoPage.xaml +++ b/samples/ControlCatalog/Pages/PlatformInfoPage.xaml @@ -7,19 +7,19 @@ d:DesignWidth="400" mc:Ignorable="d"> - - + + - + - - - - - - - - + + + + + + + + diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs index d279c0904f..134d8ba908 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs @@ -56,11 +56,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions new AvaloniaXamlIlTransitionsTypeMetadataTransformer(), new AvaloniaXamlIlResolveByNameMarkupExtensionReplacer() ); + InsertAfter( + new AvaloniaXamlIlOnPlatformTransformer()); InsertBefore( new OnFormFactorTransformer()); - InsertBefore( - new OnPlatformTransformer()); InsertAfter( new XDataTypeTransformer()); diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlOnPlatformTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlOnPlatformTransformer.cs new file mode 100644 index 0000000000..78f18393ba --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlOnPlatformTransformer.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Emit; +using XamlX; +using XamlX.Ast; +using XamlX.Emit; +using XamlX.IL; +using XamlX.IL.Emitters; +using XamlX.Transform; +using XamlX.Transform.Transformers; +using XamlX.TypeSystem; + +namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers; + +internal class AvaloniaXamlIlOnPlatformTransformer : IXamlAstTransformer +{ + private const string OnPlatformFqn = "Avalonia.Markup.Xaml:Avalonia.Markup.Xaml.MarkupExtensions.OnPlatformExtension"; + private const string OnFqn = "Avalonia.Markup.Xaml:Avalonia.Markup.Xaml.MarkupExtensions.On"; + + public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) + { + if (node is XamlAstXamlPropertyValueNode targetPropertyNode + && targetPropertyNode.Values.OfType().FirstOrDefault() is + { + Value: XamlAstObjectNode { Type: XamlAstClrTypeReference { Type: { } type } } objectNode + } + && type.GetFqn().StartsWith(OnPlatformFqn)) + { + var typeArgument = type.GenericArguments?.FirstOrDefault(); + var targetType = typeArgument ?? objectNode.Type.GetClrType(); + if (targetType is null) + { + throw new XamlParseException( + "Unable to find OnPlatform property type. Try to set x:TypeArguments on the markup extension.", + node); + } + + IXamlAstNode defaultValue = null; + var values = new Dictionary(); + + var directives = objectNode.Children.OfType().ToArray(); + + foreach (var child in objectNode.Arguments.Take(1)) + { + defaultValue = new XamlAstXamlPropertyValueNode(child, targetPropertyNode.Property, child); + } + + foreach (var extProp in objectNode.Children.OfType()) + { + var onObjs = extProp.Values.OfType() + .Where(o => o.Type.GetClrType().GetFqn() == OnFqn).ToArray(); + if (onObjs.Any()) + { + foreach (var onObj in onObjs) + { + var platformStr = (onObj.Children.OfType() + .SingleOrDefault(v => v.Property.GetClrProperty().Name == "Platform") + ?.Values.Single() as XamlAstTextNode)? + .Text; + if (string.IsNullOrWhiteSpace(platformStr)) + { + throw new XamlParseException("On.Platform string must be set", onObj); + } + + var content = onObj.Children.OfType() + .SingleOrDefault(v => v.Property.GetClrProperty().Name == "Content"); + if (content is null) + { + throw new XamlParseException("On content object must be set", onObj); + } + + var transformed = TransformNode(targetPropertyNode.Property, content.Values, + typeArgument, directives, content); + foreach (var platform in platformStr.Split(new[] { ',' }, + StringSplitOptions.RemoveEmptyEntries)) + { + values.Add(platform.Trim().ToUpperInvariant(), transformed); + } + } + } + else + { + + var platformStr = extProp.Property.GetClrProperty().Name.Trim().ToUpperInvariant(); + var transformed = TransformNode(targetPropertyNode.Property, extProp.Values, + typeArgument, directives, extProp); + if (platformStr.Equals("default", StringComparison.OrdinalIgnoreCase)) + { + defaultValue = transformed; + } + else + { + values.Add(platformStr, transformed); + } + } + } + + return new XamlIlOnPlatformExtensionNode( + defaultValue, values, + new XamlAstClrTypeReference(node, targetType, false), + node); + } + + return node; + + XamlAstXamlPropertyValueNode TransformNode( + IXamlAstPropertyReference property, + IReadOnlyCollection values, + IXamlType suggestedType, + IReadOnlyCollection directives, + IXamlLineInfo line) + { + if (suggestedType is not null) + { + values = values + .Select(v => XamlTransformHelpers + .TryGetCorrectlyTypedValue(context, v, suggestedType, out var converted) + ? converted : v) + .ToArray(); + } + + if (directives.Any()) + { + foreach (var value in values) + { + if (value is XamlAstObjectNode xamlAstObjectNode) + { + xamlAstObjectNode.Children.AddRange(directives); + } + } + } + + return new XamlAstXamlPropertyValueNode(line, property, values); + } + } + + private sealed class XamlIlOnPlatformExtensionNode : XamlAstNode, IXamlAstValueNode, + IXamlAstEmitableNode, IXamlAstManipulationNode + { + private IXamlAstNode _defaultValue; + private readonly IXamlAstNode[] _values; + private readonly string[] _valuePlatforms; + + public XamlIlOnPlatformExtensionNode( + IXamlAstNode defaultValue, + IDictionary values, + IXamlAstTypeReference targetType, + IXamlLineInfo info) : base(info) + { + _defaultValue = defaultValue; + _values = values.Values.ToArray(); + _valuePlatforms = values.Keys.ToArray(); + Type = targetType; + } + + public override void VisitChildren(IXamlAstVisitor visitor) + { + _defaultValue = _defaultValue?.Visit(visitor); + VisitList(_values, visitor); + } + + public IXamlAstTypeReference Type { get; } + + public XamlILNodeEmitResult Emit(XamlEmitContext context, + IXamlILEmitter codeGen) + { + var operatingSystemClass = + context.Configuration.TypeSystem.GetType( + "Avalonia.Markup.Xaml.MarkupExtensions.OnPlatformExtensionHelper"); + var isOSPlatformMethod = operatingSystemClass + .FindMethod(m => m.IsStatic && m.Parameters.Count == 1 && m.Name == "IsOSPlatform"); + + var ret = codeGen.DefineLabel(); + + for (var index = 0; index < _valuePlatforms.Length; index++) + { + var platform = _valuePlatforms[index]; + var propertyNode = _values[index]; + + var next = codeGen.DefineLabel(); + codeGen.Ldstr(platform); + codeGen.EmitCall(isOSPlatformMethod); + codeGen.Brfalse(next); + context.Emit(propertyNode, codeGen, null); + codeGen.Br(ret); + codeGen.MarkLabel(next); + } + + if (_defaultValue is not null) + { + codeGen.Emit(OpCodes.Nop); + context.Emit(_defaultValue, codeGen, null); + } + else + { + codeGen.Pop(); + } + + codeGen.MarkLabel(ret); + + return XamlILNodeEmitResult.Void(1); + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/OnFormFactorTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/OnFormFactorTransformer.cs index e2eaaa3a9f..07570d33bd 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/OnFormFactorTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/OnFormFactorTransformer.cs @@ -11,50 +11,50 @@ internal class OnFormFactorTransformer : IXamlAstTransformer { public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) { - if (node is XamlAstObjectNode xmlobj - && xmlobj.Type is XamlAstXmlTypeReference xmlref - && xmlref.Name.StartsWith("OnFormFactor") - && !xmlref.GenericArguments.Any()) - { - IXamlType propertyType = null; - - if (context.ParentNodes().FirstOrDefault() is XamlAstXamlPropertyValueNode parentPropertyValueNode) - { - var property = (XamlAstNamePropertyReference)parentPropertyValueNode.Property; - var declaringType = TypeReferenceResolver.ResolveType(context, (XamlAstXmlTypeReference)property.DeclaringType, context.StrictMode); - propertyType = declaringType.Type.GetAllProperties().First(p => p.Name == property.Name).PropertyType; - } - else if (context.ParentNodes().FirstOrDefault() is XamlAstObjectNode parentNode) - { - var parentType = parentNode.Type is XamlAstClrTypeReference clrType - ? clrType.Type - : TypeReferenceResolver.ResolveType(context, (XamlAstXmlTypeReference)parentNode.Type, context.StrictMode).Type; - var contentProperty = context.Configuration.FindContentProperty(parentType); - propertyType = contentProperty.PropertyType; - } - - if (propertyType is null) - { - throw new InvalidOperationException("Unable to find OnFormFactor property type"); - } - - xmlobj.Type = TypeReferenceResolver.ResolveType(context, xmlref.XmlNamespace, xmlref.Name, - xmlref.IsMarkupExtension, new[] { new XamlAstClrTypeReference(xmlref, propertyType, false) }, - xmlref, context.StrictMode); - } - - if (node is XamlAstNamePropertyReference xmlprop - && xmlprop.DeclaringType is XamlAstXmlTypeReference propxmlref - && propxmlref.Name.StartsWith("OnFormFactor") - && !propxmlref.GenericArguments.Any()) - { - var expectedType = context.ParentNodes().OfType() - .First(n => n.Type is XamlAstClrTypeReference clrRef && clrRef.Type.Name.StartsWith("OnFormFactor") - || n.Type is XamlAstXmlTypeReference xmlRef && xmlRef.Name.StartsWith("OnFormFactor")) - .Type; - xmlprop.DeclaringType = expectedType; - xmlprop.TargetType = expectedType; - } + // if (node is XamlAstObjectNode xmlobj + // && xmlobj.Type is XamlAstXmlTypeReference xmlref + // && xmlref.Name.StartsWith("OnFormFactor") + // && !xmlref.GenericArguments.Any()) + // { + // IXamlType propertyType = null; + // + // if (context.ParentNodes().FirstOrDefault() is XamlAstXamlPropertyValueNode parentPropertyValueNode) + // { + // var property = (XamlAstNamePropertyReference)parentPropertyValueNode.Property; + // var declaringType = TypeReferenceResolver.ResolveType(context, (XamlAstXmlTypeReference)property.DeclaringType, context.StrictMode); + // propertyType = declaringType.Type.GetAllProperties().First(p => p.Name == property.Name).PropertyType; + // } + // else if (context.ParentNodes().FirstOrDefault() is XamlAstObjectNode parentNode) + // { + // var parentType = parentNode.Type is XamlAstClrTypeReference clrType + // ? clrType.Type + // : TypeReferenceResolver.ResolveType(context, (XamlAstXmlTypeReference)parentNode.Type, context.StrictMode).Type; + // var contentProperty = context.Configuration.FindContentProperty(parentType); + // propertyType = contentProperty.PropertyType; + // } + // + // if (propertyType is null) + // { + // throw new InvalidOperationException("Unable to find OnFormFactor property type"); + // } + // + // xmlobj.Type = TypeReferenceResolver.ResolveType(context, xmlref.XmlNamespace, xmlref.Name, + // xmlref.IsMarkupExtension, new[] { new XamlAstClrTypeReference(xmlref, propertyType, false) }, + // xmlref, context.StrictMode); + // } + // + // if (node is XamlAstNamePropertyReference xmlprop + // && xmlprop.DeclaringType is XamlAstXmlTypeReference propxmlref + // && propxmlref.Name.StartsWith("OnFormFactor") + // && !propxmlref.GenericArguments.Any()) + // { + // var expectedType = context.ParentNodes().OfType() + // .First(n => n.Type is XamlAstClrTypeReference clrRef && clrRef.Type.Name.StartsWith("OnFormFactor") + // || n.Type is XamlAstXmlTypeReference xmlRef && xmlRef.Name.StartsWith("OnFormFactor")) + // .Type; + // xmlprop.DeclaringType = expectedType; + // xmlprop.TargetType = expectedType; + // } // if (node is XamlAstObjectNode onobj // && onobj.Type is XamlAstXmlTypeReference onref diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/OnPlatformTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/OnPlatformTransformer.cs deleted file mode 100644 index 9aa18b70d2..0000000000 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/OnPlatformTransformer.cs +++ /dev/null @@ -1,128 +0,0 @@ -using System; -using System.Linq; -using XamlX.Ast; -using XamlX.Transform; -using XamlX.Transform.Transformers; -using XamlX.TypeSystem; - -namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers; - -internal class OnPlatformTransformer : IXamlAstTransformer -{ - public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) - { - if (node is XamlAstObjectNode xmlobj - && xmlobj.Type is XamlAstXmlTypeReference xmlref - && xmlref.Name.StartsWith("OnPlatform") - && !xmlref.GenericArguments.Any()) - { - IXamlType propertyType = null; - - if (context.ParentNodes().FirstOrDefault() is XamlAstXamlPropertyValueNode parentPropertyValueNode) - { - var property = (XamlAstNamePropertyReference)parentPropertyValueNode.Property; - var declaringType = TypeReferenceResolver.ResolveType(context, (XamlAstXmlTypeReference)property.DeclaringType, context.StrictMode); - propertyType = declaringType.Type.GetAllProperties().First(p => p.Name == property.Name).PropertyType; - } - else if (context.ParentNodes().FirstOrDefault() is XamlAstObjectNode parentNode) - { - var parentType = parentNode.Type is XamlAstClrTypeReference clrType - ? clrType.Type - : TypeReferenceResolver.ResolveType(context, (XamlAstXmlTypeReference)parentNode.Type, context.StrictMode).Type; - var contentProperty = context.Configuration.FindContentProperty(parentType); - propertyType = contentProperty.PropertyType; - } - - if (propertyType is null) - { - throw new InvalidOperationException("Unable to find OnPlatform property type"); - } - - xmlobj.Type = TypeReferenceResolver.ResolveType(context, xmlref.XmlNamespace, xmlref.Name, - xmlref.IsMarkupExtension, new[] { new XamlAstClrTypeReference(xmlref, propertyType, false) }, - xmlref, context.StrictMode); - } - - if (node is XamlAstNamePropertyReference xmlprop - && xmlprop.DeclaringType is XamlAstXmlTypeReference propxmlref - && propxmlref.Name.StartsWith("OnPlatform") - && !propxmlref.GenericArguments.Any()) - { - var expectedType = context.ParentNodes().OfType() - .First(n => n.Type is XamlAstClrTypeReference clrRef && clrRef.Type.Name.StartsWith("OnPlatform") - || n.Type is XamlAstXmlTypeReference xmlRef && xmlRef.Name.StartsWith("OnPlatform")) - .Type; - xmlprop.DeclaringType = expectedType; - xmlprop.TargetType = expectedType; - } - - // if (node is XamlAstObjectNode onobj - // && onobj.Type is XamlAstXmlTypeReference onref - // && onref.Name == "On") - // { - // var platformStr = (onobj.Children.OfType() - // .FirstOrDefault(v => ((XamlAstNamePropertyReference)v.Property).Name == "Platform")?.Values.Single() as XamlAstTextNode)? - // .Text; - // if (string.IsNullOrWhiteSpace(platformStr)) - // { - // throw new InvalidOperationException("On.Platform string must be set"); - // } - // var content = onobj.Children.OfType().FirstOrDefault(); - // if (content is null) - // { - // throw new InvalidOperationException("On content object must be set"); - // } - // - // var parentOnPlatformObject = context.ParentNodes().OfType() - // .First(n => n.Type is XamlAstClrTypeReference clrRef && clrRef.Type.Name.StartsWith("OnPlatform") - // || n.Type is XamlAstXmlTypeReference xmlRef && xmlRef.Name.StartsWith("OnPlatform")); - // parentOnPlatformObject.Children.Remove(onobj); - // foreach (var platform in platformStr.Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries)) - // { - // var propertyNode = new XamlAstXamlPropertyValueNode(onobj, - // new XamlAstNamePropertyReference(onobj, parentOnPlatformObject.Type, platform.Trim(), - // parentOnPlatformObject.Type), content); - // parentOnPlatformObject.Children.Add(propertyNode); - // } - // - // return parentOnPlatformObject.Children.Last(); - // } - // if (node is XamlAstXamlPropertyValueNode propNode) - // { - // var type = (propNode.Property as XamlAstNamePropertyReference).TargetType as XamlAstXmlTypeReference; - // - // propNode.VisitChildren(new OnPlatformGenericTypeVisitor(type)); - // - // return node; - // } - - return node; - } - - private class OnPlatformGenericTypeVisitor : IXamlAstVisitor - { - private readonly XamlAstXmlTypeReference _type; - public OnPlatformGenericTypeVisitor(IXamlAstTypeReference type) - { - - } - - public IXamlAstNode Visit(IXamlAstNode node) - { - if (node is XamlAstXmlTypeReference { Name: "OnPlatform" } xmlref) - { - xmlref.GenericArguments.Add(_type); - } - - return node; - } - - public void Push(IXamlAstNode node) - { - } - - public void Pop() - { - } - } -} diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github b/src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github index 2c3b53a3db..f1bfeb0c57 160000 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github @@ -1 +1 @@ -Subproject commit 2c3b53a3db61018db620418fab509ba1d168ff24 +Subproject commit f1bfeb0c575cf05175debbd518153d2674dd90b7 diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/OnPlatformExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/OnPlatformExtension.cs index c371c93892..607f3ecc07 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/OnPlatformExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/OnPlatformExtension.cs @@ -1,12 +1,30 @@ #nullable enable using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; +using System.Runtime.InteropServices; using Avalonia.Metadata; using Avalonia.Platform; namespace Avalonia.Markup.Xaml.MarkupExtensions; +public static class OnPlatformExtensionHelper +{ + // TEMPORARY, to replace with XAML compiler namespace helpers + public static bool IsOSPlatform(string platform) + { + var runtimeInfo = AvaloniaLocator.Current.GetRequiredService().GetRuntimeInfo(); + return platform switch + { + "WINDOWS" => runtimeInfo.OperatingSystem == OperatingSystemType.WinNT, + "MACOS" => runtimeInfo.OperatingSystem == OperatingSystemType.OSX, + _ => runtimeInfo.OperatingSystem.ToString().Equals(platform, StringComparison.OrdinalIgnoreCase) + }; + //return RuntimeInformation.IsOSPlatform(OSPlatform.Create(platform)); + } +} + public class On { public string Platform { get; set; } = "Unknown"; @@ -15,6 +33,18 @@ public class On public object? Content { get; set; } } +public class OnPlatformExtension : OnPlatformExtension +{ + public OnPlatformExtension() + { + + } + + public OnPlatformExtension(object defaultValue) : base(defaultValue) + { + } +} + public class OnPlatformExtension : IAddChild { private readonly Dictionary _values = new(); @@ -26,7 +56,7 @@ public class OnPlatformExtension : IAddChild public OnPlatformExtension() { - + } public TReturn? Default { get => _values.TryGetValue(nameof(Default), out var value) ? value : default; set { _values[nameof(Default)] = value; } } @@ -38,6 +68,7 @@ public class OnPlatformExtension : IAddChild public TReturn? Browser { get => _values.TryGetValue(nameof(Browser), out var value) ? value : default; set { _values[nameof(Browser)] = value; } } public object? ProvideValue() { + throw new NotSupportedException(); if (!_values.Any()) { throw new InvalidOperationException("OnPlatformExtension requires a value to be specified for at least one platform or Default."); @@ -52,7 +83,7 @@ public class OnPlatformExtension : IAddChild var runtimeInfo = AvaloniaLocator.Current.GetRequiredService().GetRuntimeInfo(); TReturn val; - + switch (runtimeInfo.OperatingSystem) { case OperatingSystemType.WinNT: @@ -75,21 +106,21 @@ public class OnPlatformExtension : IAddChild return (val, true); } break; - + case OperatingSystemType.Android: if (_values.TryGetValue(nameof(Android), out val)) { return (val, true); } break; - + case OperatingSystemType.iOS: if (_values.TryGetValue(nameof(iOS), out val)) { return (val, true); } break; - + case OperatingSystemType.Browser: if (_values.TryGetValue(nameof(Browser), out val)) { @@ -97,7 +128,7 @@ public class OnPlatformExtension : IAddChild } break; } - + if (_values.TryGetValue(nameof(Default), out val)) { return (val, true); diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/OnPlatformExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/OnPlatformExtensionTests.cs index 1e5ec415c0..834a5ef274 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/OnPlatformExtensionTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/OnPlatformExtensionTests.cs @@ -42,7 +42,8 @@ public class OnPlatformExtensionTests : XamlTestBase var xaml = @" - + "; var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml); @@ -125,7 +126,7 @@ public class OnPlatformExtensionTests : XamlTestBase } } - [Fact(Skip = "Fix me")] + [Fact] public void Should_Respect_Custom_TypeArgument() { using (AvaloniaLocator.EnterScope()) @@ -170,6 +171,27 @@ public class OnPlatformExtensionTests : XamlTestBase } } + [Fact] + public void Should_Allow_Nester_On_Platform_Markup_Extensions() + { + using (AvaloniaLocator.EnterScope()) + { + AvaloniaLocator.CurrentMutable.Bind() + .ToConstant(new TestRuntimePlatform(OperatingSystemType.WinNT)); + + var xaml = @" + + +"; + + var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml); + var border = (Border)userControl.Content!; + + Assert.Equal(new Thickness(10), border.Margin); + } + } + [Fact] public void Should_Support_Xml_Syntax() { @@ -224,13 +246,15 @@ public class OnPlatformExtensionTests : XamlTestBase } } - [Fact] - public void Should_Support_Special_On_Syntax() + [Theory] + [InlineData(OperatingSystemType.OSX, "#ff506070")] + [InlineData(OperatingSystemType.Linux, "#000")] + public void Should_Support_Special_On_Syntax(OperatingSystemType os, string color) { using (AvaloniaLocator.EnterScope()) { AvaloniaLocator.CurrentMutable.Bind() - .ToConstant(new TestRuntimePlatform(OperatingSystemType.OSX)); + .ToConstant(new TestRuntimePlatform(os)); var xaml = @" () + .ToConstant(new TestRuntimePlatform(OperatingSystemType.WinNT)); + + var xaml = @" + + + +