Browse Source

Merge pull request #9434 from AvaloniaUI/compiledbinding-template-from-selector

CompiledBinding resolve template type from selector
feature/remove-legacy-renderers
Nikita Tsukanov 4 years ago
committed by GitHub
parent
commit
058200fe64
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlMetadataRemover.cs
  2. 53
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs
  3. 34
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs

5
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlMetadataRemover.cs

@ -1,4 +1,3 @@
using System.Linq;
using XamlX.Ast; using XamlX.Ast;
using XamlX.Transform; using XamlX.Transform;
@ -8,8 +7,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{ {
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
{ {
if (node is AvaloniaXamlIlTargetTypeMetadataNode targetType) while (node is AvaloniaXamlIlTargetTypeMetadataNode targetType)
return targetType.Value; node = targetType.Value;
return node; return node;
} }

53
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs

@ -128,13 +128,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
break; break;
} }
case SelectorGrammar.ChildSyntax child: case SelectorGrammar.ChildSyntax child:
result = new XamlIlCombinatorSelector(result, XamlIlCombinatorSelector.SelectorType.Child); result = new XamlIlCombinatorSelector(result, XamlIlCombinatorSelector.CombinatorSelectorType.Child);
break; break;
case SelectorGrammar.DescendantSyntax descendant: case SelectorGrammar.DescendantSyntax descendant:
result = new XamlIlCombinatorSelector(result, XamlIlCombinatorSelector.SelectorType.Descendant); result = new XamlIlCombinatorSelector(result, XamlIlCombinatorSelector.CombinatorSelectorType.Descendant);
break; break;
case SelectorGrammar.TemplateSyntax template: case SelectorGrammar.TemplateSyntax template:
result = new XamlIlCombinatorSelector(result, XamlIlCombinatorSelector.SelectorType.Template); result = new XamlIlCombinatorSelector(result, XamlIlCombinatorSelector.CombinatorSelectorType.Template);
break; break;
case SelectorGrammar.NotSyntax not: case SelectorGrammar.NotSyntax not:
result = new XamlIlNotSelector(result, Create(not.Argument, typeResolver)); result = new XamlIlNotSelector(result, Create(not.Argument, typeResolver));
@ -186,18 +186,50 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
=> TypeReferenceResolver.ResolveType(context, $"{p}:{n}", true, node, true)); => TypeReferenceResolver.ResolveType(context, $"{p}:{n}", true, node, true));
pn.Values[0] = selector; pn.Values[0] = selector;
return new AvaloniaXamlIlTargetTypeMetadataNode(on, var templateType = GetLastTemplateTypeFromSelector(selector);
var styleNode = new AvaloniaXamlIlTargetTypeMetadataNode(on,
new XamlAstClrTypeReference(selector, selector.TargetType, false), new XamlAstClrTypeReference(selector, selector.TargetType, false),
AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style); AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style);
return templateType switch
{
null => styleNode,
_ => new AvaloniaXamlIlTargetTypeMetadataNode(styleNode,
new XamlAstClrTypeReference(styleNode, templateType, false),
AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.ControlTemplate)
};
} }
} private static IXamlType GetLastTemplateTypeFromSelector(XamlIlSelectorNode node)
{
while (node is not null)
{
if (node is XamlIlCombinatorSelector
{
SelectorType: XamlIlCombinatorSelector.CombinatorSelectorType.Template
} templateSelector)
{
if (templateSelector.Previous is XamlIlNestingSelector nestingSelector)
{
return nestingSelector.TargetType;
}
if (templateSelector.Previous is XamlIlTypeSelector typeSelector)
{
return typeSelector.TargetType;
}
return null;
}
node = node.Previous;
}
return null;
}
}
abstract class XamlIlSelectorNode : XamlAstNode, IXamlAstValueNode, IXamlAstEmitableNode<IXamlILEmitter, XamlILNodeEmitResult> abstract class XamlIlSelectorNode : XamlAstNode, IXamlAstValueNode, IXamlAstEmitableNode<IXamlILEmitter, XamlILNodeEmitResult>
{ {
protected XamlIlSelectorNode Previous { get; } internal XamlIlSelectorNode Previous { get; }
public abstract IXamlType TargetType { get; } public abstract IXamlType TargetType { get; }
public XamlIlSelectorNode(XamlIlSelectorNode previous, public XamlIlSelectorNode(XamlIlSelectorNode previous,
@ -289,19 +321,20 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
class XamlIlCombinatorSelector : XamlIlSelectorNode class XamlIlCombinatorSelector : XamlIlSelectorNode
{ {
private readonly SelectorType _type; private readonly CombinatorSelectorType _type;
public enum SelectorType public enum CombinatorSelectorType
{ {
Child, Child,
Descendant, Descendant,
Template Template
} }
public XamlIlCombinatorSelector(XamlIlSelectorNode previous, SelectorType type) : base(previous) public XamlIlCombinatorSelector(XamlIlSelectorNode previous, CombinatorSelectorType type) : base(previous)
{ {
_type = type; _type = type;
} }
public CombinatorSelectorType SelectorType => _type;
public override IXamlType TargetType => null; public override IXamlType TargetType => null;
protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen) protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{ {

34
tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs

@ -754,6 +754,40 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
} }
} }
[Fact]
public void ResolvesRelativeSourceBindingFromStyleSelector()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
<TextBox xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
InnerLeftContent='Hello'>
<TextBox.Styles>
<Style Selector='TextBox'>
<Setter Property='Template'>
<ControlTemplate>
<StackPanel>
<ContentPresenter x:Name='Content' />
<TextPresenter x:Name='PART_TextPresenter' />
</StackPanel>
</ControlTemplate>
</Setter>
<Style Selector='^ /template/ ContentPresenter#Content'>
<Setter Property='Content' Value='{CompiledBinding InnerLeftContent, RelativeSource={RelativeSource TemplatedParent}}' />
</Style>
</Style>
</TextBox.Styles>
</TextBox>";
var textBox = AvaloniaRuntimeXamlLoader.Parse<TextBox>(xaml);
textBox.Measure(new Size(10, 10));
var result = textBox.GetTemplateChildren().OfType<ContentPresenter>().First();
Assert.Equal(textBox.InnerLeftContent, result.Content);
}
}
[Fact] [Fact]
public void ResolvesElementNameInTemplate() public void ResolvesElementNameInTemplate()
{ {

Loading…
Cancel
Save