Browse Source

Merge branch 'master' into feature/textCompat

pull/9276/head
Benedikt Stebner 3 years ago
committed by GitHub
parent
commit
6e972cc3b2
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs
  2. 34
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTargetTypeMetadataTransformer.cs
  3. 25
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs
  4. 51
      tests/Avalonia.Markup.Xaml.UnitTests/SetterTests.cs

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

@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
using XamlX;
using XamlX.Ast;
@ -51,6 +52,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
new AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer(),
new AvaloniaXamlIlBindingPathParser(),
new AvaloniaXamlIlPropertyPathTransformer(),
new AvaloniaXamlIlSetterTargetTypeMetadataTransformer(),
new AvaloniaXamlIlSetterTransformer(),
new AvaloniaXamlIlConstructorServiceProviderTransformer(),
new AvaloniaXamlIlTransitionsTypeMetadataTransformer(),

34
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTargetTypeMetadataTransformer.cs

@ -0,0 +1,34 @@
using System.Linq;
using XamlX;
using XamlX.Ast;
using XamlX.Transform;
using XamlX.Transform.Transformers;
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
internal class AvaloniaXamlIlSetterTargetTypeMetadataTransformer : IXamlAstTransformer
{
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
{
if (node is XamlAstObjectNode on
&& on.Children.FirstOrDefault(c => c is XamlAstXmlDirective
{
Namespace: XamlNamespaces.Xaml2006,
Name: "SetterTargetType"
}) is { } typeDirective)
{
var value = ((XamlAstXmlDirective)typeDirective).Values.Single();
var type = value is XamlTypeExtensionNode typeNode ? typeNode.Value
: value is XamlAstTextNode tn ? TypeReferenceResolver.ResolveType(context, tn.Text, false, tn, true)
: null;
on.Children.Remove(typeDirective);
if (type is null)
{
throw new XamlParseException("Unable to resolve SetterTargetType type", typeDirective);
}
return new AvaloniaXamlIlTargetTypeMetadataNode(on, type, AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style);
}
return node;
}
}

25
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs

@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using XamlX;
using XamlX.Ast;
using XamlX.Emit;
using XamlX.IL;
@ -8,7 +9,6 @@ using XamlX.TypeSystem;
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{
using XamlParseException = XamlX.XamlParseException;
class AvaloniaXamlIlSetterTransformer : IXamlAstTransformer
{
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
@ -17,10 +17,24 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
&& on.Type.GetClrType().FullName == "Avalonia.Styling.Setter"))
return node;
var targetTypeNode = context.ParentNodes()
IXamlType targetType = null;
IXamlLineInfo lineInfo = null;
var styleParent = context.ParentNodes()
.OfType<AvaloniaXamlIlTargetTypeMetadataNode>()
.FirstOrDefault(x => x.ScopeType == AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style) ??
throw new XamlParseException("Can not find parent Style Selector or ControlTemplate TargetType", node);
.FirstOrDefault(x => x.ScopeType == AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style);
if (styleParent != null)
{
targetType = styleParent.TargetType.GetClrType()
?? throw new XamlParseException("Can not find parent Style Selector or ControlTemplate TargetType. If setter is not part of the style, you can set x:SetterTargetType directive on its parent.", node);
lineInfo = on;
}
if (targetType == null)
{
throw new XamlParseException("Could not determine target type of Setter", node);
}
IXamlType propType = null;
var property = @on.Children.OfType<XamlAstXamlPropertyValueNode>()
@ -31,9 +45,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
if (propertyName == null)
throw new XamlParseException("Setter.Property must be a string", node);
var avaloniaPropertyNode = XamlIlAvaloniaPropertyHelper.CreateNode(context, propertyName,
new XamlAstClrTypeReference(targetTypeNode, targetTypeNode.TargetType.GetClrType(), false), property.Values[0]);
new XamlAstClrTypeReference(lineInfo, targetType, false), property.Values[0]);
property.Values = new List<IXamlAstValueNode> {avaloniaPropertyNode};
propType = avaloniaPropertyNode.AvaloniaPropertyType;
}

51
tests/Avalonia.Markup.Xaml.UnitTests/SetterTests.cs

@ -0,0 +1,51 @@
using Avalonia.Controls;
using Avalonia.Styling;
using Avalonia.UnitTests;
using Xunit;
namespace Avalonia.Markup.Xaml.UnitTests;
public class SetterTests : XamlTestBase
{
[Fact]
public void SetterTargetType_Should_Understand_xType_Extensions()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
<Animation xmlns='https://github.com/avaloniaui' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' x:SetterTargetType='{x:Type ContentControl}'>
<KeyFrame>
<Setter Property='Content' Value='{Binding}'/>
</KeyFrame>
<KeyFrame>
<Setter Property='Content' Value='{Binding}'/>
</KeyFrame>
</Animation>";
var animation = (Animation.Animation)AvaloniaRuntimeXamlLoader.Load(xaml);
var setter = (Setter)animation.Children[0].Setters[0];
Assert.Equal(typeof(ContentControl), setter.Property.OwnerType);
}
}
[Fact]
public void SetterTargetType_Should_Understand_Type_From_Xmlns()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
<av:Animation xmlns:av='https://github.com/avaloniaui' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' x:SetterTargetType='av:ContentControl'>
<av:KeyFrame>
<av:Setter Property='Content' Value='{av:Binding}'/>
</av:KeyFrame>
<av:KeyFrame>
<av:Setter Property='Content' Value='{av:Binding}'/>
</av:KeyFrame>
</av:Animation>";
var animation = (Animation.Animation)AvaloniaRuntimeXamlLoader.Load(xaml);
var setter = (Setter)animation.Children[0].Setters[0];
Assert.Equal(typeof(ContentControl), setter.Property.OwnerType);
}
}
}
Loading…
Cancel
Save