Browse Source

Add AvaloniaXamlIlSetterTargetTypeMetadataTransformer to allow SetterTargetType

pull/8572/head
Max Katz 3 years ago
parent
commit
0c84ae68b9
  1. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs
  2. 34
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTargetTypeMetadataTransformer.cs
  3. 23
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs
  4. 47
      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;
}
}

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

@ -9,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)
@ -28,29 +27,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
if (styleParent != null)
{
targetType = styleParent.TargetType.GetClrType()
?? throw new XamlParseException("Can not resolve parent Style Selector type", node);
?? throw new XamlParseException("Can not resolve parent Style Selector type. If setter is not part of the style, you can set x:SetterTargetType directive on its parent.", node);
lineInfo = on;
}
else
{
foreach (var p in context.ParentNodes().OfType<XamlAstObjectNode>())
{
for (var index = 0; index < p.Children.Count; index++)
{
if (p.Children[index] is XamlAstXmlDirective d &&
d.Namespace == XamlNamespaces.Xaml2006 &&
d.Name == "SetterTargetType")
{
targetType = context.Configuration.TypeSystem.GetType(((XamlAstTextNode)d.Values[0]).Text);
lineInfo = d;
break;
}
}
if (targetType != null) break;
}
}
if (targetType == null)
{

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

@ -1,20 +1,19 @@
using System.Linq;
using Avalonia.Data;
using Avalonia.Controls;
using Avalonia.Styling;
using Avalonia.UnitTests;
using Xunit;
namespace Avalonia.Markup.Xaml.UnitTests
namespace Avalonia.Markup.Xaml.UnitTests;
public class SetterTests : XamlTestBase
{
public class SetterTests : XamlTestBase
[Fact]
public void SetterTargetType_Should_Understand_xType_Extensions()
{
[Fact]
public void Setter_Should_Work_Outside_Of_Style_With_SetterTargetType_Attribute()
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
<Animation xmlns='https://github.com/avaloniaui' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' x:SetterTargetType='Avalonia.Controls.Button'>
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>
@ -22,11 +21,31 @@ namespace Avalonia.Markup.Xaml.UnitTests
<Setter Property='Content' Value='{Binding}'/>
</KeyFrame>
</Animation>";
var animation = (Animation.Animation)AvaloniaRuntimeXamlLoader.Load(xaml);
var setter = (Setter)animation.Children[0].Setters[0];
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.IsType<Binding>(setter.Value);
}
Assert.Equal(typeof(ContentControl), setter.Property.OwnerType);
}
}
}

Loading…
Cancel
Save