11 changed files with 526 additions and 159 deletions
@ -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); |
|||
} |
|||
} |
|||
} |
|||
@ -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() |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -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…
Reference in new issue