Ver Fonte

Enable transforming old-style RelativeSource/ElementName properties in CompiledBindings to element path nodes during XamlIl compilation.

Jeremy Koritzinsky há 6 anos atrás
pai
commit
c0c1ccb544

+ 2 - 0
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@@ -18,6 +18,7 @@
         <Compile Include="MarkupExtensions\CompiledBindingExtension.cs" />
         <Compile Include="MarkupExtensions\CompiledBindings\ArrayElementPlugin.cs" />
         <Compile Include="MarkupExtensions\CompiledBindings\CompiledBindingPath.cs" />
+        <Compile Include="MarkupExtensions\CompiledBindings\FindVisualAncestorNode.cs" />
         <Compile Include="MarkupExtensions\CompiledBindings\ObservableStreamPlugin.cs" />
         <Compile Include="MarkupExtensions\CompiledBindings\PropertyInfoAccessorFactory.cs" />
         <Compile Include="MarkupExtensions\CompiledBindings\PropertyInfoAccessorPlugin.cs" />
@@ -57,6 +58,7 @@
         <Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlPropertyPathTransformer.cs" />
         <Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlRootObjectScopeTransformer.cs" />
         <Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlTransformInstanceAttachedProperties.cs" />
+        <Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlTransformSyntheticCompiledBindingMembers.cs" />
         <Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlTransitionsTypeMetadataTransformer.cs" />
         <Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlWellKnownTypes.cs" />
         <Compile Include="XamlIl\CompilerExtensions\XamlIlAvaloniaPropertyHelper.cs" />

+ 20 - 0
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs

@@ -37,6 +37,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
                     case ArrayElementPathElement arr:
                         node = new PropertyAccessorNode(CommonPropertyNames.IndexerName, enableValidation, new ArrayElementPlugin(arr.Indices, arr.ElementType));
                         break;
+                    case VisualAncestorPathElement visualAncestor:
+                        node = new FindVisualAncestorNode(visualAncestor.AncestorType, visualAncestor.Level);
+                        break;
                     case AncestorPathElement ancestor:
                         node = new FindAncestorNode(ancestor.AncestorType, ancestor.Level);
                         break;
@@ -101,6 +104,11 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
             _elements.Add(new AncestorPathElement(ancestorType, level));
             return this;
         }
+        public CompiledBindingPathBuilder VisualAncestor(Type ancestorType, int level)
+        {
+            _elements.Add(new VisualAncestorPathElement(ancestorType, level));
+            return this;
+        }
 
         public CompiledBindingPathBuilder ElementName(INameScope nameScope, string name)
         {
@@ -177,6 +185,18 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
         public int Level { get; }
     }
 
+    internal class VisualAncestorPathElement : ICompiledBindingPathElement, IControlSourceBindingPathElement
+    {
+        public VisualAncestorPathElement(Type ancestorType, int level)
+        {
+            AncestorType = ancestorType;
+            Level = level;
+        }
+
+        public Type AncestorType { get; }
+        public int Level { get; }
+    }
+
     internal class ElementNameElement : ICompiledBindingPathElement, IControlSourceBindingPathElement
     {
         public ElementNameElement(INameScope nameScope, string name)

+ 52 - 0
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/FindVisualAncestorNode.cs

@@ -0,0 +1,52 @@
+using System;
+using Avalonia.Data.Core;
+using Avalonia.VisualTree;
+
+namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
+{
+    class FindVisualAncestorNode : ExpressionNode
+    {
+        private readonly int _level;
+        private readonly Type _ancestorType;
+        private IDisposable _subscription;
+
+        public FindVisualAncestorNode(Type ancestorType, int level)
+        {
+            _level = level;
+            _ancestorType = ancestorType;
+        }
+
+        public override string Description
+        {
+            get
+            {
+                if (_ancestorType == null)
+                {
+                    return $"$visualparent[{_level}]";
+                }
+                else
+                {
+                    return $"$visualparent[{_ancestorType.Name}, {_level}]";
+                }
+            }
+        }
+
+        protected override void StartListeningCore(WeakReference<object> reference)
+        {
+            if (reference.TryGetTarget(out object target) && target is IVisual visual)
+            {
+                _subscription = VisualLocator.Track(visual, _level, _ancestorType).Subscribe(ValueChanged);
+            }
+            else
+            {
+                _subscription = null;
+            }
+        }
+
+        protected override void StopListeningCore()
+        {
+            _subscription?.Dispose();
+            _subscription = null;
+        }
+    }
+}

+ 5 - 6
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompiler.cs

@@ -37,26 +37,25 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             
             // Targeted
 
-            InsertBefore<XamlIlPropertyReferenceResolver>(new AvaloniaXamlIlTransformInstanceAttachedProperties());
+            InsertBefore<XamlIlPropertyReferenceResolver>(
+                new AvaloniaXamlIlTransformInstanceAttachedProperties(),
+                new AvaloniaXamlIlTransformSyntheticCompiledBindingMembers());
             InsertAfter<XamlIlPropertyReferenceResolver>(new AvaloniaXamlIlAvaloniaPropertyResolver());
             
 
 
             InsertBefore<XamlIlContentConvertTransformer>(
+                new AvaloniaXamlIlBindingPathParser(),
                 new AvaloniaXamlIlSelectorTransformer(),
+                new AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer(),
                 new AvaloniaXamlIlPropertyPathTransformer(),
                 new AvaloniaXamlIlSetterTransformer(),
-                new AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer(),
                 new AvaloniaXamlIlConstructorServiceProviderTransformer(),
                 new AvaloniaXamlIlTransitionsTypeMetadataTransformer()
             );
 
             // After everything else
 
-            InsertBefore<XamlIlConvertPropertyValuesToAssignmentsTransformer>(
-                new AvaloniaXamlIlBindingPathParser()
-            );
-
             InsertBefore<XamlIlNewObjectTransformer>(
                 new AddNameScopeRegistration(),
                 new AvaloniaXamlIlDataContextTypeTransformer(),

+ 228 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathParser.cs

@@ -4,8 +4,10 @@ using System.Linq;
 using System.Text;
 using Avalonia.Markup.Parsers;
 using Avalonia.Utilities;
+using XamlIl;
 using XamlIl.Ast;
 using XamlIl.Transform;
+using XamlIl.Transform.Transformers;
 using XamlIl.TypeSystem;
 
 namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
@@ -16,10 +18,18 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
         {
             if (node is XamlIlAstObjectNode binding && binding.Type.GetClrType().Equals(context.GetAvaloniaTypes().CompiledBindingExtension))
             {
+                var convertedNode = ConvertLongFormPropertiesToBindingExpressionNode(context, binding);
+
                 if (binding.Arguments.Count > 0 && binding.Arguments[0] is XamlIlAstTextNode bindingPathText)
                 {
                     var reader = new CharacterReader(bindingPathText.Text.AsSpan());
                     var (nodes, _) = BindingExpressionGrammar.Parse(ref reader);
+
+                    if (convertedNode != null)
+                    {
+                        nodes.Insert(nodes.TakeWhile(x => x is BindingExpressionGrammar.ITransformNode).Count(), convertedNode);
+                    }
+
                     binding.Arguments[0] = new ParsedBindingPathNode(bindingPathText, context.GetAvaloniaTypes().CompiledBindingPath, nodes);
                 }
                 else
@@ -31,6 +41,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
                     {
                         var reader = new CharacterReader(pathValue.Text.AsSpan());
                         var (nodes, _) = BindingExpressionGrammar.Parse(ref reader);
+
+                        if (convertedNode != null)
+                        {
+                            nodes.Insert(nodes.TakeWhile(x => x is BindingExpressionGrammar.ITransformNode).Count(), convertedNode);
+                        }
+
                         bindingPathAssignment.Values[0] = new ParsedBindingPathNode(pathValue, context.GetAvaloniaTypes().CompiledBindingPath, nodes);
                     }
                 }
@@ -38,6 +54,201 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 
             return node;
         }
+
+        private static BindingExpressionGrammar.INode ConvertLongFormPropertiesToBindingExpressionNode(
+            XamlIlAstTransformationContext context,
+            XamlIlAstObjectNode binding)
+        {
+            BindingExpressionGrammar.INode convertedNode = null;
+
+            var syntheticCompiledBindingProperties = binding.Children.OfType<XamlIlAstXamlPropertyValueNode>()
+                .Where(v => v.Property is AvaloniaSyntheticCompiledBindingProperty)
+                .ToList();
+
+            var elementNameProperty = syntheticCompiledBindingProperties
+                .FirstOrDefault(v =>
+                    v.Property is AvaloniaSyntheticCompiledBindingProperty prop
+                    && prop.Name == SyntheticCompiledBindingPropertyName.ElementName);
+
+            var relativeSourceProperty = syntheticCompiledBindingProperties
+                .FirstOrDefault(v =>
+                    v.Property is AvaloniaSyntheticCompiledBindingProperty prop
+                    && prop.Name == SyntheticCompiledBindingPropertyName.RelativeSource);
+
+            if (elementNameProperty?.Values[0] is XamlIlAstTextNode elementName)
+            {
+                convertedNode = new BindingExpressionGrammar.NameNode { Name = elementName.Text };
+            }
+            else if (elementNameProperty != null)
+            {
+                throw new XamlIlParseException($"Invalid ElementName '{elementNameProperty.Values[0]}'.", elementNameProperty.Values[0]);
+            }
+
+            if (GetRelativeSourceObjectFromAssignment(
+                context,
+                relativeSourceProperty,
+                out var relativeSourceObject))
+            {
+                if (convertedNode != null)
+                {
+                    throw new XamlIlParseException("Both ElementName and RelativeSource specified as a binding source. Only one property is allowed.", binding);
+                }
+
+                var mode = relativeSourceObject.Children
+                    .OfType<XamlIlAstXamlPropertyValueNode>()
+                    .FirstOrDefault(x => x.Property.GetClrProperty().Name == "Mode")
+                    ?.Values[0] is XamlIlAstTextNode modeAssignedValue ? modeAssignedValue.Text : null;
+                if (relativeSourceObject.Arguments.Count == 0 && mode == null)
+                {
+                    mode = "FindAncestor";
+                }
+
+                if (mode == "FindAncestor")
+                {
+                    var ancestorLevel = relativeSourceObject.Children
+                        .OfType<XamlIlAstXamlPropertyValueNode>()
+                        .FirstOrDefault(x => x.Property.GetClrProperty().Name == "FindAncestor")
+                        ?.Values[0] is XamlIlAstTextNode ancestorLevelText ? int.Parse(ancestorLevelText.Text) - 1 : 0;
+
+                    var treeType = relativeSourceObject.Children
+                        .OfType<XamlIlAstXamlPropertyValueNode>()
+                        .FirstOrDefault(x => x.Property.GetClrProperty().Name == "Tree")
+                        ?.Values[0] is XamlIlAstTextNode treeTypeValue ? treeTypeValue.Text : "Visual";
+
+                    var ancestorTypeName = relativeSourceObject.Children
+                        .OfType<XamlIlAstXamlPropertyValueNode>()
+                        .FirstOrDefault(x => x.Property.GetClrProperty().Name == "AncestorType")
+                        ?.Values[0] as XamlIlAstTextNode;
+
+                    IXamlIlType ancestorType = null;
+                    if (ancestorTypeName is null)
+                    {
+                        if (treeType == "Visual")
+                        {
+                            throw new XamlIlParseException("AncestorType must be set for RelativeSourceMode.FindAncestor when searching the visual tree.", relativeSourceObject);
+                        }
+                        else if (treeType == "Logical")
+                        {
+                            var styledElementType = context.GetAvaloniaTypes().StyledElement;
+                            ancestorType = context
+                                .ParentNodes()
+                                .OfType<XamlIlAstObjectNode>()
+                                .Where(x => styledElementType.IsAssignableFrom(x.Type.GetClrType()))
+                                .ElementAtOrDefault(ancestorLevel)
+                                ?.Type.GetClrType();
+
+                            if (ancestorType is null)
+                            {
+                                throw new XamlIlParseException("Unable to resolve implicit ancestor type based on XAML tree.", relativeSourceObject);
+                            }
+                        }
+                    }
+                    else
+                    {
+                        ancestorType = XamlIlTypeReferenceResolver.ResolveType(
+                                            context,
+                                            ancestorTypeName.Text,
+                                            false,
+                                            ancestorTypeName,
+                                            true).GetClrType();
+                    }
+
+                    if (treeType == "Visual")
+                    {
+                        convertedNode = new VisualAncestorBindingExpressionNode
+                        {
+                            Type = ancestorType,
+                            Level = ancestorLevel
+                        };
+                    }
+                    else if (treeType == "Logical")
+                    {
+                        convertedNode = new LogicalAncestorBindingExpressionNode
+                        {
+                            Type = ancestorType,
+                            Level = ancestorLevel
+                        };
+                    }
+                    else
+                    {
+                        throw new XamlIlParseException($"Unknown tree type '{treeType}'.", binding);
+                    }
+                }
+                else if (mode == "DataContext")
+                {
+                    convertedNode = null;
+                }
+                else if (mode == "Self")
+                {
+                    convertedNode = new BindingExpressionGrammar.SelfNode();
+                }
+                else if (mode == "TemplatedParent")
+                {
+                    var parentType = context.ParentNodes().OfType<AvaloniaXamlIlTargetTypeMetadataNode>()
+                        .FirstOrDefault(x =>
+                            x.ScopeType == AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.ControlTemplate)
+                        ?.TargetType.GetClrType();
+
+                    if (parentType is null)
+                    {
+                        throw new XamlIlParseException("A binding with a TemplatedParent RelativeSource has to be in a ControlTemplate.", binding);
+                    }
+
+                    convertedNode = new TemplatedParentBindingExpressionNode { Type = parentType };
+                }
+                else
+                {
+                    throw new XamlIlParseException($"Unknown RelativeSource mode '{mode}'.", binding);
+                }
+            }
+
+            if (elementNameProperty != null)
+            {
+                binding.Children.Remove(elementNameProperty);
+            }
+            if (relativeSourceProperty != null)
+            {
+                binding.Children.Remove(relativeSourceProperty);
+            }
+
+            return convertedNode;
+        }
+
+        private static bool GetRelativeSourceObjectFromAssignment(
+            XamlIlAstTransformationContext context,
+            XamlIlAstXamlPropertyValueNode relativeSourceProperty,
+            out XamlIlAstObjectNode relativeSourceObject)
+        {
+            relativeSourceObject = null;
+            if (relativeSourceProperty is null)
+            {
+                return false;
+            }
+
+            if (relativeSourceProperty.Values[0] is XamlIlMarkupExtensionNode me)
+            {
+                if (me.Type.GetClrType() != context.GetAvaloniaTypes().RelativeSource)
+                {
+                    throw new XamlIlParseException($"Expected an object of type 'Avalonia.Data.RelativeSource'. Found a object of type '{me.Type.GetClrType().GetFqn()}'", me);
+                }
+
+                relativeSourceObject = (XamlIlAstObjectNode)me.Value;
+                return true;
+            }
+
+            if (relativeSourceProperty.Values[0] is XamlIlAstObjectNode on)
+            {
+                if (on.Type.GetClrType() != context.GetAvaloniaTypes().RelativeSource)
+                {
+                    throw new XamlIlParseException($"Expected an object of type 'Avalonia.Data.RelativeSource'. Found a object of type '{on.Type.GetClrType().GetFqn()}'", on);
+                }
+
+                relativeSourceObject = on;
+                return true;
+            }
+
+            return false;
+        }
     }
 
     class ParsedBindingPathNode : XamlIlAstNode, IXamlIlAstValueNode
@@ -53,4 +264,21 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
 
         public IList<BindingExpressionGrammar.INode> Path { get; }
     }
+
+    class VisualAncestorBindingExpressionNode : BindingExpressionGrammar.INode
+    {
+        public IXamlIlType Type { get; set; }
+        public int Level { get; set; }
+    }
+
+    class LogicalAncestorBindingExpressionNode : BindingExpressionGrammar.INode
+    {
+        public IXamlIlType Type { get; set; }
+        public int Level { get; set; }
+    }
+
+    class TemplatedParentBindingExpressionNode : BindingExpressionGrammar.INode
+    {
+        public IXamlIlType Type { get; set; }
+    }
 }

+ 52 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransformSyntheticCompiledBindingMembers.cs

@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using XamlIl;
+using XamlIl.Ast;
+using XamlIl.Transform;
+
+namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
+{
+    class AvaloniaXamlIlTransformSyntheticCompiledBindingMembers : IXamlIlAstTransformer
+    {
+        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
+        {
+            if (node is XamlIlAstNamePropertyReference prop
+               && prop.TargetType is XamlIlAstClrTypeReference targetRef
+               && targetRef.GetClrType().Equals(context.GetAvaloniaTypes().CompiledBindingExtension))
+            {
+                if (prop.Name == "ElementName")
+                {
+                    return new AvaloniaSyntheticCompiledBindingProperty(node,
+                        SyntheticCompiledBindingPropertyName.ElementName);
+                }
+                else if (prop.Name == "RelativeSource")
+                {
+                    return new AvaloniaSyntheticCompiledBindingProperty(node,
+                        SyntheticCompiledBindingPropertyName.RelativeSource);
+                }
+            }
+
+            return node;
+        }
+    }
+
+    enum SyntheticCompiledBindingPropertyName
+    {
+        ElementName,
+        RelativeSource
+    }
+
+    class AvaloniaSyntheticCompiledBindingProperty : XamlIlAstNode, IXamlIlAstPropertyReference
+    {
+        public SyntheticCompiledBindingPropertyName Name { get; }
+
+        public AvaloniaSyntheticCompiledBindingProperty(
+            IXamlIlLineInfo lineInfo,
+            SyntheticCompiledBindingPropertyName name)
+            : base(lineInfo)
+        {
+            Name = name;
+        }
+    }
+}

+ 3 - 0
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs

@@ -39,6 +39,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
         public IXamlIlType IItemsPresenterHost { get; }
         public IXamlIlType BindingExtension { get; }
 
+        public IXamlIlType RelativeSource { get; }
+
         public AvaloniaXamlIlWellKnownTypes(XamlIlTransformerConfiguration cfg)
         {
             XamlIlTypes = cfg.WellKnownTypes;
@@ -91,6 +93,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
             DataTemplate = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.Templates.DataTemplate");
             IItemsPresenterHost = cfg.TypeSystem.GetType("Avalonia.Controls.Presenters.IItemsPresenterHost");
             BindingExtension = cfg.TypeSystem.GetType("Avalonia.Markup.Xaml.MarkupExtensions.BindingExtension");
+            RelativeSource = cfg.TypeSystem.GetType("Avalonia.Data.RelativeSource");
         }
     }
 

+ 57 - 2
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlBindingPathHelper.cs

@@ -118,6 +118,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                         else
                         {
                             var clrProperty = targetType.GetAllProperties().FirstOrDefault(p => p.Name == propName.PropertyName);
+
+                            if (clrProperty is null)
+                            {
+                                throw new XamlIlParseException($"Unable to resolve property of name '{propName.PropertyName}' on type '{targetType}'.", lineInfo);
+                            }
                             nodes.Add(new XamlIlClrPropertyPathElementNode(clrProperty));
                         }
                         break;
@@ -176,8 +181,38 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
                     case BindingExpressionGrammar.SelfNode _:
                         nodes.Add(new SelfPathElementNode(targetType));
                         break;
+                    case VisualAncestorBindingExpressionNode visualAncestor:
+                        nodes.Add(new FindVisualAncestorPathElementNode(visualAncestor.Type, visualAncestor.Level));
+                        break;
+                    case TemplatedParentBindingExpressionNode templatedParent:
+                        var templatedParentField = context.GetAvaloniaTypes().StyledElement.GetAllFields()
+                            .FirstOrDefault(f => f.IsStatic && f.IsPublic && f.Name == "TemplatedParentProperty");
+                        nodes.Add(new XamlIlAvaloniaPropertyPropertyPathElementNode(
+                            templatedParentField,
+                            templatedParent.Type));
+                        break;
                     case BindingExpressionGrammar.AncestorNode ancestor:
-                        nodes.Add(new FindAncestorPathElementNode(GetType(ancestor.Namespace, ancestor.TypeName), ancestor.Level));
+                        if (ancestor.Namespace is null && ancestor.TypeName is null)
+                        {
+                            var styledElementType = context.GetAvaloniaTypes().StyledElement;
+                            var ancestorType = context
+                                .ParentNodes()
+                                .OfType<XamlIlAstObjectNode>()
+                                .Where(x => styledElementType.IsAssignableFrom(x.Type.GetClrType()))
+                                .ElementAtOrDefault(ancestor.Level)
+                                ?.Type.GetClrType();
+
+                            if (ancestorType is null)
+                            {
+                                throw new XamlIlParseException("Unable to resolve implicit ancestor type based on XAML tree.", lineInfo);
+                            }
+
+                            nodes.Add(new FindAncestorPathElementNode(ancestorType, ancestor.Level));
+                        }
+                        else
+                        {
+                            nodes.Add(new FindAncestorPathElementNode(GetType(ancestor.Namespace, ancestor.TypeName), ancestor.Level));
+                        }
                         break;
                     case BindingExpressionGrammar.NameNode elementName:
                         IXamlIlType elementType = null;
@@ -351,6 +386,26 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             }
         }
 
+        class FindVisualAncestorPathElementNode : IXamlIlBindingPathElementNode
+        {
+            private readonly int _level;
+
+            public FindVisualAncestorPathElementNode(IXamlIlType ancestorType, int level)
+            {
+                Type = ancestorType;
+                _level = level;
+            }
+
+            public IXamlIlType Type { get; }
+
+            public void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
+            {
+                codeGen.Ldtype(Type)
+                    .Ldc_I4(_level)
+                    .EmitCall(context.GetAvaloniaTypes().CompiledBindingPathBuilder.FindMethod(m => m.Name == "VisualAncestor"));
+            }
+        }
+
         class ElementNamePathElementNode : IXamlIlBindingPathElementNode
         {
             private readonly string _name;
@@ -390,7 +445,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
             {
                 codeGen.Ldsfld(_field);
                 context.Configuration.GetExtra<XamlIlPropertyInfoAccessorFactoryEmitter>()
-                    .EmitLoadInpcPropertyAccessorFactory(context, codeGen);
+                    .EmitLoadAvaloniaPropertyAccessorFactory(context, codeGen);
                 codeGen.EmitCall(context.GetAvaloniaTypes()
                     .CompiledBindingPathBuilder.FindMethod(m => m.Name == "Property"));
             }

+ 3 - 1
src/Markup/Avalonia.Markup/Markup/Parsers/BindingExpressionGrammar.cs

@@ -345,6 +345,8 @@ namespace Avalonia.Markup.Parsers
 
         public interface INode {}
 
+        public interface ITransformNode {}
+
         public class EmptyExpressionNode : INode { }
 
         public class PropertyNameNode : INode
@@ -364,7 +366,7 @@ namespace Avalonia.Markup.Parsers
             public IList<string> Arguments { get; set; }
         }
 
-        public class NotNode : INode {}
+        public class NotNode : INode, ITransformNode {}
 
         public class StreamNode : INode {}
 

+ 55 - 0
tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs

@@ -439,6 +439,61 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
                 Assert.Equal(dataContext.StringProperty, textBlock.Text);
             }
         }
+
+        [Fact]
+        public void ResolvesElementNameBindingFromLongForm()
+        {
+            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            {
+                var xaml = @"
+<Window xmlns='https://github.com/avaloniaui'
+        xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
+        xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
+        x:DataType='local:TestDataContext'>
+    <StackPanel>
+        <TextBlock Text='{CompiledBinding StringProperty}' x:Name='text' />
+        <TextBlock Text='{CompiledBinding Text, ElementName=text}' x:Name='text2' />
+    </StackPanel>
+</Window>";
+                var loader = new AvaloniaXamlLoader();
+                var window = (Window)loader.Load(xaml);
+                var textBlock = window.FindControl<TextBlock>("text2");
+
+                var dataContext = new TestDataContext
+                {
+                    StringProperty = "foobar"
+                };
+
+                window.DataContext = dataContext;
+
+                Assert.Equal(dataContext.StringProperty, textBlock.Text);
+            }
+        }
+
+        [Fact]
+        public void ResolvesRelativeSourceBindingLongForm()
+        {
+            using (UnitTestApplication.Start(TestServices.StyledWindow))
+            {
+                var xaml = @"
+<Window xmlns='https://github.com/avaloniaui'
+        xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
+        xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
+        x:DataType='local:TestDataContext'
+        Title='test'>
+    <TextBlock Text='{CompiledBinding Title, RelativeSource={RelativeSource AncestorType=Window}}' x:Name='text'/>
+</Window>";
+                var loader = new AvaloniaXamlLoader();
+                var window = (Window)loader.Load(xaml);
+                var target = window.FindControl<TextBlock>("text");
+
+                window.ApplyTemplate();
+                window.Presenter.ApplyTemplate();
+                target.ApplyTemplate();
+
+                Assert.Equal("test", target.Text);
+            }
+        }
     }
 
     public class TestDataContext