diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlMetadataRemover.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlMetadataRemover.cs index a09e13389a..288574d116 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlMetadataRemover.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlMetadataRemover.cs @@ -1,4 +1,3 @@ -using System.Linq; using XamlX.Ast; using XamlX.Transform; @@ -8,8 +7,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) { - if (node is AvaloniaXamlIlTargetTypeMetadataNode targetType) - return targetType.Value; + while (node is AvaloniaXamlIlTargetTypeMetadataNode targetType) + node = targetType.Value; return node; } diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs index 70209fb3ad..467dced080 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs @@ -128,13 +128,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers break; } case SelectorGrammar.ChildSyntax child: - result = new XamlIlCombinatorSelector(result, XamlIlCombinatorSelector.SelectorType.Child); + result = new XamlIlCombinatorSelector(result, XamlIlCombinatorSelector.CombinatorSelectorType.Child); break; case SelectorGrammar.DescendantSyntax descendant: - result = new XamlIlCombinatorSelector(result, XamlIlCombinatorSelector.SelectorType.Descendant); + result = new XamlIlCombinatorSelector(result, XamlIlCombinatorSelector.CombinatorSelectorType.Descendant); break; case SelectorGrammar.TemplateSyntax template: - result = new XamlIlCombinatorSelector(result, XamlIlCombinatorSelector.SelectorType.Template); + result = new XamlIlCombinatorSelector(result, XamlIlCombinatorSelector.CombinatorSelectorType.Template); break; case SelectorGrammar.NotSyntax not: 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)); pn.Values[0] = selector; - return new AvaloniaXamlIlTargetTypeMetadataNode(on, + var templateType = GetLastTemplateTypeFromSelector(selector); + + var styleNode = new AvaloniaXamlIlTargetTypeMetadataNode(on, new XamlAstClrTypeReference(selector, selector.TargetType, false), 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 { - protected XamlIlSelectorNode Previous { get; } + internal XamlIlSelectorNode Previous { get; } public abstract IXamlType TargetType { get; } public XamlIlSelectorNode(XamlIlSelectorNode previous, @@ -289,19 +321,20 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers class XamlIlCombinatorSelector : XamlIlSelectorNode { - private readonly SelectorType _type; + private readonly CombinatorSelectorType _type; - public enum SelectorType + public enum CombinatorSelectorType { Child, Descendant, Template } - public XamlIlCombinatorSelector(XamlIlSelectorNode previous, SelectorType type) : base(previous) + public XamlIlCombinatorSelector(XamlIlSelectorNode previous, CombinatorSelectorType type) : base(previous) { _type = type; } + public CombinatorSelectorType SelectorType => _type; public override IXamlType TargetType => null; protected override void DoEmit(XamlEmitContext context, IXamlILEmitter codeGen) { diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs index 87e4c77686..77067fa517 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs +++ b/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 = @" + + + + + +"; + + var textBox = AvaloniaRuntimeXamlLoader.Parse(xaml); + textBox.Measure(new Size(10, 10)); + + var result = textBox.GetTemplateChildren().OfType().First(); + Assert.Equal(textBox.InnerLeftContent, result.Content); + } + } + [Fact] public void ResolvesElementNameInTemplate() {