Browse Source

Reenable form factor markup extension with some tests

release/11.0.0-preview3
Max Katz 3 years ago
parent
commit
3d4b0ae91c
  1. 18
      samples/ControlCatalog/Pages/PlatformInfoPage.xaml
  2. 13
      src/Avalonia.Base/Platform/IRuntimePlatform.cs
  3. 5
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs
  4. 159
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlOnFormFactorTransformer.cs
  5. 15
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlOnPlatformTransformer.cs
  6. 4
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
  7. 128
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/OnFormFactorTransformer.cs
  8. 21
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/OnFormFactorExtension.cs
  9. 8
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/OnPlatformExtension.cs
  10. 5
      src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs
  11. 309
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/OnFormFactorExtensionTests.cs

18
samples/ControlCatalog/Pages/PlatformInfoPage.xaml

@ -7,19 +7,17 @@
d:DesignWidth="400"
mc:Ignorable="d">
<StackPanel Spacing="20">
<!-- <TextBlock Text="{OnFormFactor Unknown, Mobile=Mobile, Desktop=Desktop}" /> -->
<TextBlock Text="{Binding PlatformInfo}" />
<StackPanel TextElement.Foreground="White">
<!-- <StackPanel Orientation="Horizontal"> -->
<!-- <Border Height="100" Width="100" Background="{OnFormFactor Gray, Desktop=Green}"> -->
<!-- <TextBlock Text="Desktop" /> -->
<!-- </Border> -->
<!-- <Border Height="100" Width="100" Background="{OnFormFactor Gray, Mobile=Green}"> -->
<!-- <TextBlock Text="Mobile" /> -->
<!-- </Border> -->
<!-- </StackPanel> -->
<StackPanel Orientation="Horizontal">
<Border Height="100" Width="100" Background="{OnFormFactor Gray, Desktop=Green}">
<TextBlock Text="Desktop" />
</Border>
<Border Height="100" Width="100" Background="{OnFormFactor Gray, Mobile=Green}">
<TextBlock Text="Mobile" />
</Border>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Border Height="100" Width="100" Background="{OnPlatform Gray, Windows=Green}">
<TextBlock Text="Windows" />

13
src/Avalonia.Base/Platform/IRuntimePlatform.cs

@ -17,13 +17,16 @@ namespace Avalonia.Platform
IntPtr Address { get; }
int Size { get; }
bool IsDisposed { get; }
}
[Unstable]
public struct RuntimePlatformInfo
{
public OperatingSystemType OperatingSystem { get; set; }
public FormFactorType FormFactor => IsDesktop ? FormFactorType.Desktop :
IsMobile ? FormFactorType.Mobile : FormFactorType.Unknown;
public bool IsDesktop { get; set; }
public bool IsMobile { get; set; }
public bool IsBrowser { get; set; }
@ -44,4 +47,12 @@ namespace Avalonia.Platform
iOS,
Browser
}
[Unstable]
public enum FormFactorType
{
Unknown,
Desktop,
Mobile
}
}

5
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs

@ -57,10 +57,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
new AvaloniaXamlIlResolveByNameMarkupExtensionReplacer()
);
InsertAfter<ResolveContentPropertyTransformer>(
new AvaloniaXamlIlOnPlatformTransformer());
new AvaloniaXamlIlOnPlatformTransformer(),
new AvaloniaXamlIlOnFormFactorTransformer());
InsertBefore<TypeReferenceResolver>(
new OnFormFactorTransformer());
InsertAfter<TypeReferenceResolver>(
new XDataTypeTransformer());

159
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlOnFormFactorTransformer.cs

@ -0,0 +1,159 @@
using System;
using System.Collections.Generic;
using System.Linq;
using XamlX;
using XamlX.Ast;
using XamlX.Emit;
using XamlX.IL;
using XamlX.Transform;
using XamlX.TypeSystem;
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
internal class AvaloniaXamlIlOnFormFactorTransformer : IXamlAstTransformer
{
private const string OnFormFactorFqn = "Avalonia.Markup.Xaml:Avalonia.Markup.Xaml.MarkupExtensions.OnFormFactorExtension";
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
{
if (node is XamlAstXamlPropertyValueNode targetPropertyNode
&& targetPropertyNode.Values.OfType<XamlMarkupExtensionNode>().FirstOrDefault() is
{
Value: XamlAstObjectNode { Type: XamlAstClrTypeReference { Type: { } type } } objectNode
}
&& type.GetFqn().StartsWith(OnFormFactorFqn))
{
var typeArgument = type.GenericArguments?.FirstOrDefault();
OnFormFactorDefaultNode defaultValue = null;
var values = new List<OnFormFactorBranchNode>();
var directives = objectNode.Children.OfType<XamlAstXmlDirective>().ToArray();
foreach (var child in objectNode.Arguments.Take(1))
{
defaultValue = new OnFormFactorDefaultNode(new XamlAstXamlPropertyValueNode(child, targetPropertyNode.Property, child));
}
foreach (var extProp in objectNode.Children.OfType<XamlAstXamlPropertyValueNode>())
{
var propName = extProp.Property.GetClrProperty().Name.Trim();
var transformed = TransformNode(targetPropertyNode.Property, extProp.Values,
typeArgument, directives, extProp);
if (propName.Equals("DEFAULT", StringComparison.OrdinalIgnoreCase))
{
defaultValue = new OnFormFactorDefaultNode(transformed);
}
else if (propName != "CONTENT")
{
values.Add(new OnFormFactorBranchNode(
ConvertPlatformNode(propName, extProp),
transformed));
}
}
return new AvaloniaXamlIlConditionalNode(defaultValue, values, node);
}
return node;
XamlConstantNode ConvertPlatformNode(string propName, IXamlLineInfo li)
{
var enumType = context.GetAvaloniaTypes().FormFactorType;
if (TypeSystemHelpers.TryGetEnumValueNode(enumType, propName, li, false, out var enumConstantNode))
{
return enumConstantNode;
}
throw new XamlParseException($"Unable to parse form factor name: \"{propName}\"", li);
}
XamlAstXamlPropertyValueNode TransformNode(
IXamlAstPropertyReference property,
IReadOnlyCollection<IXamlAstValueNode> values,
IXamlType suggestedType,
IReadOnlyCollection<XamlAstXmlDirective> 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 OnFormFactorBranchNode : AvaloniaXamlIlConditionalBranchNode
{
private IXamlAstNode _platform;
private IXamlAstNode _value;
public OnFormFactorBranchNode(
IXamlAstNode platform,
IXamlAstNode value)
: base(value)
{
_platform = platform;
_value = value;
}
public override void VisitChildren(IXamlAstVisitor visitor)
{
_platform = _platform.Visit(visitor);
_value = _value.Visit(visitor);
}
public override void EmitCondition(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{
var enumType = context.GetAvaloniaTypes().FormFactorType;
var isOnFormFactorMethod = context.GetAvaloniaTypes().IsOnFormFactorMethod;
codeGen.Ldloc(context.ContextLocal);
context.Emit(_platform, codeGen, enumType);
codeGen.EmitCall(isOnFormFactorMethod);
}
public override void EmitBody(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{
context.Emit(_value, codeGen, null);
}
}
private sealed class OnFormFactorDefaultNode : AvaloniaXamlIlConditionalDefaultNode
{
private IXamlAstNode _value;
public OnFormFactorDefaultNode(
IXamlAstNode value)
: base(value)
{
_value = value;
}
public override void VisitChildren(IXamlAstVisitor visitor)
{
_value = _value.Visit(visitor);
}
public override void EmitBody(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{
context.Emit(_value, codeGen, null);
}
}
}

15
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlOnPlatformTransformer.cs

@ -25,13 +25,6 @@ internal class AvaloniaXamlIlOnPlatformTransformer : IXamlAstTransformer
&& 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);
}
OnPlatformDefaultNode defaultValue = null;
var values = new List<OnPlatformBranchNode>();
@ -80,17 +73,17 @@ internal class AvaloniaXamlIlOnPlatformTransformer : IXamlAstTransformer
}
else
{
var platformStr = extProp.Property.GetClrProperty().Name.Trim().ToUpperInvariant();
var propName = extProp.Property.GetClrProperty().Name.Trim().ToUpperInvariant();
var transformed = TransformNode(targetPropertyNode.Property, extProp.Values,
typeArgument, directives, extProp);
if (platformStr.Equals("DEFAULT", StringComparison.OrdinalIgnoreCase))
if (propName.Equals("DEFAULT", StringComparison.OrdinalIgnoreCase))
{
defaultValue = new OnPlatformDefaultNode(transformed);
}
else if (platformStr != "CONTENT")
else if (propName != "CONTENT")
{
values.Add(new OnPlatformBranchNode(
ConvertPlatformNode(platformStr, extProp),
ConvertPlatformNode(propName, extProp),
transformed));
}
}

4
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs

@ -105,6 +105,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
public IXamlType OperatingSystemType { get; }
public IXamlMethod IsOnPlatformMethod { get; }
public IXamlType FormFactorType { get; set; }
public IXamlMethod IsOnFormFactorMethod { get; set; }
public AvaloniaXamlIlWellKnownTypes(TransformerConfiguration cfg)
{
@ -236,6 +238,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
OperatingSystemType = cfg.TypeSystem.GetType("Avalonia.Platform.OperatingSystemType");
IsOnPlatformMethod = RuntimeHelpers.FindMethod(m => m.IsStatic && m.Parameters.Count == 2 && m.Name == "IsOnPlatform");
FormFactorType = cfg.TypeSystem.GetType("Avalonia.Platform.FormFactorType");
IsOnFormFactorMethod = RuntimeHelpers.FindMethod(m => m.IsStatic && m.Parameters.Count == 2 && m.Name == "IsOnFormFactor");
}
}

128
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/OnFormFactorTransformer.cs

@ -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 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<XamlAstObjectNode>()
// .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
// && onref.Name == "On")
// {
// var platformStr = (onobj.Children.OfType<XamlAstXamlPropertyValueNode>()
// .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<XamlAstObjectNode>().FirstOrDefault();
// if (content is null)
// {
// throw new InvalidOperationException("On content object must be set");
// }
//
// var parentOnFormFactorObject = context.ParentNodes().OfType<XamlAstObjectNode>()
// .First(n => n.Type is XamlAstClrTypeReference clrRef && clrRef.Type.Name.StartsWith("OnFormFactor")
// || n.Type is XamlAstXmlTypeReference xmlRef && xmlRef.Name.StartsWith("OnFormFactor"));
// parentOnFormFactorObject.Children.Remove(onobj);
// foreach (var platform in platformStr.Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries))
// {
// var propertyNode = new XamlAstXamlPropertyValueNode(onobj,
// new XamlAstNamePropertyReference(onobj, parentOnFormFactorObject.Type, platform.Trim(),
// parentOnFormFactorObject.Type), content);
// parentOnFormFactorObject.Children.Add(propertyNode);
// }
//
// return parentOnFormFactorObject.Children.Last();
// }
// if (node is XamlAstXamlPropertyValueNode propNode)
// {
// var type = (propNode.Property as XamlAstNamePropertyReference).TargetType as XamlAstXmlTypeReference;
//
// propNode.VisitChildren(new OnFormFactorGenericTypeVisitor(type));
//
// return node;
// }
return node;
}
private class OnFormFactorGenericTypeVisitor : IXamlAstVisitor
{
private readonly XamlAstXmlTypeReference _type;
public OnFormFactorGenericTypeVisitor(IXamlAstTypeReference type)
{
}
public IXamlAstNode Visit(IXamlAstNode node)
{
if (node is XamlAstXmlTypeReference { Name: "OnFormFactor" } xmlref)
{
xmlref.GenericArguments.Add(_type);
}
return node;
}
public void Push(IXamlAstNode node)
{
}
public void Pop()
{
}
}
}

21
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/OnFormFactorExtension.cs

@ -6,10 +6,27 @@ using Avalonia.Platform;
namespace Avalonia.Markup.Xaml.MarkupExtensions;
public class OnFormFactorExtension : OnFormFactorExtension<object>
{
public OnFormFactorExtension()
{
}
public OnFormFactorExtension(object defaultValue) : base(defaultValue)
{
}
}
public class OnFormFactorExtension<TReturn>
{
private readonly Dictionary<string, TReturn?> _values = new();
public OnFormFactorExtension()
{
}
public OnFormFactorExtension(TReturn defaultValue)
{
Default = defaultValue;
@ -51,7 +68,7 @@ public class OnFormFactorExtension<TReturn>
var runtimeInfo = AvaloniaLocator.Current.GetRequiredService<IRuntimePlatform>().GetRuntimeInfo();
TReturn val;
if (runtimeInfo.IsDesktop)
{
if (_values.TryGetValue(nameof(Desktop), out val))
@ -67,7 +84,7 @@ public class OnFormFactorExtension<TReturn>
return (val, true);
}
}
if (_values.TryGetValue(nameof(Default), out val))
{
return (val, true);

8
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/OnPlatformExtension.cs

@ -31,14 +31,14 @@ public class OnPlatformExtension<TReturn> : IAddChild<On>
{
private readonly Dictionary<string, TReturn?> _values = new();
public OnPlatformExtension(TReturn defaultValue)
public OnPlatformExtension()
{
Default = defaultValue;
}
public OnPlatformExtension()
public OnPlatformExtension(TReturn defaultValue)
{
Default = defaultValue;
}
public TReturn? Default { get => _values.TryGetValue(nameof(Default), out var value) ? value : default; set { _values[nameof(Default)] = value; } }

5
src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs

@ -205,5 +205,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
{
return serviceProvider.GetService<IRuntimePlatform>().GetRuntimeInfo().OperatingSystem == platform;
}
public static bool IsOnFormFactor(IServiceProvider serviceProvider, FormFactorType formFactor)
{
return serviceProvider.GetService<IRuntimePlatform>().GetRuntimeInfo().FormFactor == formFactor;
}
}
}

309
tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/OnFormFactorExtensionTests.cs

@ -0,0 +1,309 @@
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Platform;
using Xunit;
namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;
public class OnFormFactorExtensionTests : XamlTestBase
{
[Fact]
public void Should_Resolve_Default_Value()
{
using (AvaloniaLocator.EnterScope())
{
AvaloniaLocator.CurrentMutable.Bind<IRuntimePlatform>()
.ToConstant(new TestRuntimePlatform(false, false));
var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<TextBlock Text='{OnFormFactor Default=""Hello World""}'/>
</UserControl>";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = (TextBlock)userControl.Content!;
Assert.Equal("Hello World", textBlock.Text);
}
}
[Fact]
public void Should_Resolve_Default_Value_From_Ctor()
{
using (AvaloniaLocator.EnterScope())
{
AvaloniaLocator.CurrentMutable.Bind<IRuntimePlatform>()
.ToConstant(new TestRuntimePlatform(false, false));
var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<TextBlock Text='{OnFormFactor ""Hello World"", Mobile=""Im Mobile""}' Margin='10' />
</UserControl>";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = (TextBlock)userControl.Content!;
Assert.Equal("Hello World", textBlock.Text);
}
}
[Theory]
[InlineData(false, true, "Im Mobile")]
[InlineData(true, false, "Im Desktop")]
[InlineData(false, false, "Default value")]
public void Should_Resolve_Expected_Value_Per_Platform(bool isDesktop, bool isMobile, string expectedResult)
{
using (AvaloniaLocator.EnterScope())
{
AvaloniaLocator.CurrentMutable.Bind<IRuntimePlatform>()
.ToConstant(new TestRuntimePlatform(isDesktop, isMobile));
var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<TextBlock Text='{OnFormFactor ""Default value"",
Mobile=""Im Mobile"", Desktop=""Im Desktop""}'/>
</UserControl>";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = (TextBlock)userControl.Content!;
Assert.Equal(expectedResult, textBlock.Text);
}
}
[Fact]
public void Should_Convert_Bcl_Type()
{
using (AvaloniaLocator.EnterScope())
{
AvaloniaLocator.CurrentMutable.Bind<IRuntimePlatform>()
.ToConstant(new TestRuntimePlatform(true, false));
var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<Border Height='{OnFormFactor Default=50.1}'/>
</UserControl>";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = (Border)userControl.Content!;
Assert.Equal(50.1, border.Height);
}
}
[Fact]
public void Should_Convert_Avalonia_Type()
{
using (AvaloniaLocator.EnterScope())
{
AvaloniaLocator.CurrentMutable.Bind<IRuntimePlatform>()
.ToConstant(new TestRuntimePlatform(true, false));
var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<Border Padding='{OnFormFactor Default=""10, 8, 10, 8""}'/>
</UserControl>";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = (Border)userControl.Content!;
Assert.Equal(new Thickness(10, 8, 10, 8), border.Padding);
}
}
[Fact]
public void Should_Respect_Custom_TypeArgument()
{
using (AvaloniaLocator.EnterScope())
{
AvaloniaLocator.CurrentMutable.Bind<IRuntimePlatform>()
.ToConstant(new TestRuntimePlatform(true, false));
var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<TextBlock DataContext='{OnFormFactor Default=""10, 10, 10, 10"", x:TypeArguments=Thickness}'/>
</UserControl>";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = (TextBlock)userControl.Content!;
Assert.Equal(new Thickness(10, 10, 10, 10), textBlock.DataContext);
}
}
[Fact]
public void Should_Allow_Nester_Markup_Extensions()
{
using (AvaloniaLocator.EnterScope())
{
AvaloniaLocator.CurrentMutable.Bind<IRuntimePlatform>()
.ToConstant(new TestRuntimePlatform(true, false));
var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<UserControl.Resources>
<SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
</UserControl.Resources>
<Border Background='{OnFormFactor Default={StaticResource brush}}'/>
</UserControl>";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = (Border)userControl.Content!;
Assert.Equal(Color.Parse("#ff506070"), ((ISolidColorBrush)border.Background!).Color);
}
}
[Fact]
public void Should_Support_Xml_Syntax()
{
using (AvaloniaLocator.EnterScope())
{
AvaloniaLocator.CurrentMutable.Bind<IRuntimePlatform>()
.ToConstant(new TestRuntimePlatform(true, false));
var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<Border>
<Border.Background>
<OnFormFactor>
<OnFormFactor.Default>
<SolidColorBrush Color='#ff506070' />
</OnFormFactor.Default>
</OnFormFactor>
</Border.Background>
</Border>
</UserControl>";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = (Border)userControl.Content!;
Assert.Equal(Color.Parse("#ff506070"), ((ISolidColorBrush)border.Background!).Color);
}
}
[Fact]
public void Should_Support_Xml_Syntax_With_Custom_TypeArguments()
{
using (AvaloniaLocator.EnterScope())
{
AvaloniaLocator.CurrentMutable.Bind<IRuntimePlatform>()
.ToConstant(new TestRuntimePlatform(true, false));
var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<Border>
<Border.Tag>
<OnFormFactor x:TypeArguments='Thickness' Default='10, 10, 10, 10' />
</Border.Tag>
</Border>
</UserControl>";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = (Border)userControl.Content!;
Assert.Equal(new Thickness(10, 10, 10, 10), border.Tag);
}
}
[Fact]
public void Should_Support_Control_Inside_Xml_Syntax()
{
using (AvaloniaLocator.EnterScope())
{
AvaloniaLocator.CurrentMutable.Bind<IRuntimePlatform>()
.ToConstant(new TestRuntimePlatform(true, false));
var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<OnFormFactor>
<OnFormFactor.Default>
<Button Content='Hello World' />
</OnFormFactor.Default>
</OnFormFactor>
</UserControl>";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var button = (Button)userControl.Content!;
Assert.Equal("Hello World", button.Content);
}
}
[Fact]
public void Should_Support_Complex_Property_Setters()
{
using (AvaloniaLocator.EnterScope())
{
AvaloniaLocator.CurrentMutable.Bind<IRuntimePlatform>()
.ToConstant(new TestRuntimePlatform(true, false));
var xaml = @"
<ResourceDictionary xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<OnFormFactor x:Key='MyKey'>
<OnFormFactor.Default>
<Button Content='Hello World' />
</OnFormFactor.Default>
</OnFormFactor>
</ResourceDictionary>";
var resourceDictionary = (ResourceDictionary)AvaloniaRuntimeXamlLoader.Load(xaml);
var button = Assert.IsType<Button>(resourceDictionary["MyKey"]);
Assert.Equal("Hello World", button.Content);
}
}
[Fact]
public void BindingExtension_Works_Inside_Of_OnFormFactor()
{
using (AvaloniaLocator.EnterScope())
{
AvaloniaLocator.CurrentMutable.Bind<IRuntimePlatform>()
.ToConstant(new TestRuntimePlatform(true, false));
var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<UserControl.Resources>
<x:String x:Key='text'>foobar</x:String>
</UserControl.Resources>
<TextBlock Name='textBlock' Text='{OnFormFactor Default={CompiledBinding Source={StaticResource text}}}'/>
</UserControl>";
var window = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
Assert.Equal("foobar", textBlock.Text);
}
}
private class TestRuntimePlatform : StandardRuntimePlatform
{
private readonly bool _isDesktop;
private readonly bool _isMobile;
public TestRuntimePlatform(bool isDesktop, bool isMobile)
{
_isDesktop = isDesktop;
_isMobile = isMobile;
}
public override RuntimePlatformInfo GetRuntimeInfo()
{
return new RuntimePlatformInfo() { IsDesktop = _isDesktop, IsMobile = _isMobile };
}
}
}
Loading…
Cancel
Save