Browse Source

WIP almost working fine, style resource binding and minor improvements

donandren 8 years ago
parent
commit
5aa306d4e8

+ 1 - 0
src/Avalonia.Base/Avalonia.Base.csproj

@@ -70,6 +70,7 @@
     <Compile Include="Logging\LogArea.cs" />
     <Compile Include="Logging\LogEventLevel.cs" />
     <Compile Include="Logging\Logger.cs" />
+    <Compile Include="Metadata\AmbientAttribute.cs" />
     <Compile Include="Metadata\TemplateContent.cs" />
     <Compile Include="Metadata\DependsOnAttribute.cs" />
     <Compile Include="Metadata\ContentAttribute.cs" />

+ 15 - 0
src/Avalonia.Base/Metadata/AmbientAttribute.cs

@@ -0,0 +1,15 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+
+namespace Avalonia.Metadata
+{
+    /// <summary>
+    /// Defines the ambient class/property 
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property, Inherited = true)]
+    public class AmbientAttribute : Attribute
+    {
+    }
+}

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

@@ -52,6 +52,8 @@
     </Compile>
     <Compile Include="AvaloniaXamlLoaderPortableXaml.cs" />
     <Compile Include="AvaloniaXamlLoader.cs" />
+    <Compile Include="PortableXaml\XamlBinding.cs" />
+    <Compile Include="PortableXaml\AttributeExtensions.cs" />
     <Compile Include="PortableXaml\AvaloniaMemberAttributeProvider.cs" />
     <Compile Include="PortableXaml\AvaloniaNameScope.cs" />
     <Compile Include="PortableXaml\AvaloniaDefaultTypeConverters.cs" />

+ 18 - 10
src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs

@@ -1,17 +1,17 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Reflection;
-using System.Text;
 using Avalonia.Controls;
 using Avalonia.Markup.Xaml.Context;
 using Avalonia.Markup.Xaml.Data;
 using Avalonia.Markup.Xaml.PortableXaml;
 using Avalonia.Platform;
 using Portable.Xaml;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
 
 namespace Avalonia.Markup.Xaml
 {
@@ -88,7 +88,14 @@ namespace Avalonia.Markup.Xaml
                     {
                         var initialize = rootInstance as ISupportInitialize;
                         initialize?.BeginInit();
-                        return Load(stream, type, rootInstance, uri);
+                        try
+                        {
+                            return Load(stream, type, rootInstance, uri);
+                        }
+                        finally
+                        {
+                            initialize?.EndInit();
+                        }
                     }
                 }
             }
@@ -197,16 +204,17 @@ namespace Avalonia.Markup.Xaml
 
         internal static object LoadFromReader(XamlReader reader, object instance)
         {
-            var writer = AvaloniaXamlObjectWriter.Create(_context, instance);
+            var writer = AvaloniaXamlObjectWriter.Create(reader.SchemaContext, instance);
 
-             XamlServices.Transform(reader, writer);
+            XamlServices.Transform(reader, writer);
 
-            return writer.Result;           
+            return writer.Result;
         }
 
         internal static object LoadFromReader(XamlReader reader)
         {
-            return XamlServices.Load(reader);
+            //return XamlServices.Load(reader);
+            return LoadFromReader(reader, null);
         }
 
         /// <summary>

+ 1 - 4
src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs

@@ -33,10 +33,7 @@ namespace Avalonia.Markup.Xaml.Converters
 
             if (typeName == null)
             {
-                var amb = context.GetService<IAmbientProvider>();
-                var sc = context.GetService<IXamlSchemaContextProvider>().SchemaContext;
-                var xamlStyleType = sc.GetXamlType(typeof(Style));
-                var style = amb.GetFirstAmbientValue(xamlStyleType) as Style;
+                var style = context.GetFirstAmbientValue<Style>();
 
                 type = style?.Selector?.TargetType;
 

+ 0 - 4
src/Markup/Avalonia.Markup.Xaml/Data/StyleResourceBinding.cs

@@ -40,10 +40,6 @@ namespace Avalonia.Markup.Xaml.Data
             object anchor = null,
             bool enableDataValidation = false)
         {
-            if (Name == "Red")
-            {
-            }
-
             var host = (target as IControl) ?? (anchor as IControl);
             var style = anchor as IStyle;
             var resource = AvaloniaProperty.UnsetValue;

+ 9 - 3
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs

@@ -7,12 +7,12 @@ using System;
 
 namespace Avalonia.Markup.Xaml.MarkupExtensions
 {
-
 #if !OMNIXAML
 
     using Portable.Xaml.Markup;
+    using PortableXaml;
 
-    [MarkupExtensionReturnType(typeof(Binding))]
+    [MarkupExtensionReturnType(typeof(IBinding))]
     public class BindingExtension : MarkupExtension
     {
         public BindingExtension()
@@ -26,7 +26,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
 
         public override object ProvideValue(IServiceProvider serviceProvider)
         {
-            return new Binding
+            var b = new Binding
             {
                 Converter = Converter,
                 ConverterParameter = ConverterParameter,
@@ -35,7 +35,10 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
                 Mode = Mode,
                 Path = Path,
                 Priority = Priority,
+                RelativeSource = RelativeSource
             };
+
+            return XamlBinding.FromMarkupExtensionContext(b, serviceProvider);
         }
 
         public IValueConverter Converter { get; set; }
@@ -54,7 +57,10 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
         public BindingPriority Priority { get; set; } = BindingPriority.LocalValue;
 
         public object Source { get; set; }
+
+        public RelativeSource RelativeSource { get; set; }
     }
+
 #else
 
     using OmniXaml;

+ 7 - 8
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs

@@ -1,21 +1,18 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
-using System;
-using System.Reactive.Linq;
-
-using Avalonia.LogicalTree;
 using Avalonia.Markup.Xaml.Data;
-using Avalonia.Styling;
-
+using System;
 
 namespace Avalonia.Markup.Xaml.MarkupExtensions
 {
+    using Avalonia.Data;
 #if !OMNIXAML
 
     using Portable.Xaml.Markup;
+    using PortableXaml;
 
-    [MarkupExtensionReturnType(typeof(StyleResourceBinding))]
+    [MarkupExtensionReturnType(typeof(IBinding))]
     public class StyleResourceExtension : MarkupExtension
     {
         public StyleResourceExtension(string name)
@@ -25,7 +22,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
 
         public override object ProvideValue(IServiceProvider serviceProvider)
         {
-            return new StyleResourceBinding(this.Name);
+            return XamlBinding.FromMarkupExtensionContext(
+                            new StyleResourceBinding(Name),
+                            serviceProvider);
         }
 
         [ConstructorArgument("name")]

+ 14 - 0
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TypeExtension.cs

@@ -1,6 +1,8 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using System;
+
 namespace Avalonia.Markup.Xaml.MarkupExtensions
 {
 #if !OMNIXAML
@@ -8,7 +10,19 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
     //TODO: check do we need something more than std Portable.xaml type??
     public class TypeExtension : Portable.Xaml.Markup.TypeExtension
     {
+        public TypeExtension()
+        {
+        }
+
+        public TypeExtension(string typeName) : base(typeName)
+        {
+
+        }
 
+        public override object ProvideValue(IServiceProvider serviceProvider)
+        {
+            return base.ProvideValue(serviceProvider);
+        }
     }
 
 #else

+ 29 - 0
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AttributeExtensions.cs

@@ -0,0 +1,29 @@
+using Avalonia.Markup.Xaml.Templates;
+using avm = Avalonia.Metadata;
+using pm = Portable.Xaml.Markup;
+
+namespace Avalonia.Markup.Xaml.PortableXaml
+{
+    internal static class AttributeExtensions
+    {
+        public static pm.XamlDeferLoadAttribute ToPortableXaml(this avm.TemplateContentAttribute attrib)
+        {
+            if (attrib == null)
+            {
+                return null;
+            }
+
+            return new pm.XamlDeferLoadAttribute(typeof(TemplateLoader), typeof(TemplateContent));
+        }
+
+        public static pm.AmbientAttribute ToPortableXaml(this avm.AmbientAttribute attrib)
+        {
+            if (attrib == null)
+            {
+                return null;
+            }
+
+            return new pm.AmbientAttribute();
+        }
+    }
+}

+ 12 - 26
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaMemberAttributeProvider.cs

@@ -1,8 +1,7 @@
-using System;
+using Portable.Xaml.ComponentModel;
+using System;
 using System.Linq;
 using System.Reflection;
-using Avalonia.Markup.Xaml.Templates;
-using Portable.Xaml.ComponentModel;
 using avm = Avalonia.Metadata;
 using pm = Portable.Xaml.Markup;
 
@@ -22,26 +21,27 @@ namespace Avalonia.Markup.Xaml.PortableXaml
 
         public object[] GetCustomAttributes(Type attributeType, bool inherit)
         {
-            object[] result = null;
+            Attribute result = null;
 
             if (attributeType == typeof(pm.XamlDeferLoadAttribute))
             {
-                var attr = GetXamlDeferLoadAttribute(inherit);
-
-                if (attr != null)
-                {
-                    result = new object[] { attr };
-                }
+                result = _info.GetCustomAttribute<avm.TemplateContentAttribute>(inherit)
+                                .ToPortableXaml();
+            }
+            else if (attributeType == typeof(pm.AmbientAttribute))
+            {
+                result = _info.GetCustomAttribute<avm.AmbientAttribute>(inherit)
+                                .ToPortableXaml();
             }
 
-            if (result == null || result.Length == 0)
+            if (result == null)
             {
                 var attr = _info.GetCustomAttributes(attributeType, inherit);
                 return (attr as object[]) ?? attr.ToArray();
             }
             else
             {
-                return result;
+                return new object[] { result };
             }
         }
 
@@ -51,19 +51,5 @@ namespace Avalonia.Markup.Xaml.PortableXaml
         }
 
         private readonly MemberInfo _info;
-
-        private Attribute GetXamlDeferLoadAttribute(bool inherit)
-        {
-            var result = _info.GetCustomAttributes(typeof(avm.TemplateContentAttribute), inherit)
-                                            .Cast<avm.TemplateContentAttribute>()
-                                            .FirstOrDefault();
-
-            if (result == null)
-            {
-                return null;
-            }
-
-            return new pm.XamlDeferLoadAttribute(typeof(TemplateLoader), typeof(TemplateContent));
-        }
     }
 }

+ 27 - 24
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs

@@ -1,11 +1,11 @@
 // Copyright (c) The Perspex Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
+using Portable.Xaml.ComponentModel;
 using System;
 using System.Linq;
 using System.Reflection;
-using Avalonia.Metadata;
-using Portable.Xaml.ComponentModel;
+using avm = Avalonia.Metadata;
 using pm = Portable.Xaml.Markup;
 
 namespace Avalonia.Markup.Xaml.PortableXaml
@@ -24,47 +24,50 @@ namespace Avalonia.Markup.Xaml.PortableXaml
 
         public object[] GetCustomAttributes(Type attributeType, bool inherit)
         {
+            Attribute result = null;
+
+            var ti = _type.GetTypeInfo();
+
             if (attributeType == typeof(pm.ContentPropertyAttribute))
             {
-                var cp = GetContentPropertyAttribute(inherit);
-
-                if (cp != null)
-                {
-                    return new object[] { cp };
-                }
+                result = GetContentPropertyAttribute(inherit);
             }
             else if (attributeType == typeof(pm.RuntimeNamePropertyAttribute))
             {
-                if (_namedType.IsAssignableFrom(_type.GetTypeInfo()))
+                if (_namedType.IsAssignableFrom(ti))
                 {
-                    return new object[]
-                         {
-                             new pm.RuntimeNamePropertyAttribute(nameof(INamed.Name))
-                         };
+                    result = new pm.RuntimeNamePropertyAttribute(nameof(INamed.Name));
                 }
             }
             else if (attributeType == typeof(TypeConverterAttribute))
             {
-                var attribs = _type.GetTypeInfo().GetCustomAttributes(attributeType, inherit);
+                result = ti.GetCustomAttribute(attributeType, inherit);
 
-                if (attribs?.Any() != true)
+                if (result == null)
                 {
                     var convType = AvaloniaDefaultTypeConverters.GetTypeConverter(_type);
 
                     if (convType != null)
                     {
-                        return new object[]
-                        {
-                            new TypeConverterAttribute(convType)
-                        };
+                        result = new TypeConverterAttribute(convType);
                     }
                 }
-
-                return (attribs as object[]) ?? attribs.ToArray();
+            }
+            else if (attributeType == typeof(pm.AmbientAttribute))
+            {
+                result = ti.GetCustomAttribute<avm.AmbientAttribute>(inherit)
+                                                    .ToPortableXaml();
             }
 
-            var attr = _type.GetTypeInfo().GetCustomAttributes(attributeType, inherit);
-            return (attr as object[]) ?? attr.ToArray();
+            if (result == null)
+            {
+                var attr = ti.GetCustomAttributes(attributeType, inherit);
+                return (attr as object[]) ?? attr.ToArray();
+            }
+            else
+            {
+                return new object[] { result };
+            }
         }
 
         public bool IsDefined(Type attributeType, bool inherit)
@@ -83,7 +86,7 @@ namespace Avalonia.Markup.Xaml.PortableXaml
             while (type != null)
             {
                 var properties = type.GetTypeInfo().DeclaredProperties
-                    .Where(x => x.GetCustomAttribute<ContentAttribute>() != null);
+                    .Where(x => x.GetCustomAttribute<avm.ContentAttribute>() != null);
                 string result = null;
 
                 foreach (var property in properties)

+ 169 - 14
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs

@@ -1,4 +1,7 @@
-using Portable.Xaml;
+using Avalonia.Data;
+using Portable.Xaml;
+using System.Collections.Generic;
+using System.Linq;
 
 namespace Avalonia.Markup.Xaml.PortableXaml
 {
@@ -37,12 +40,16 @@ namespace Avalonia.Markup.Xaml.PortableXaml
 
         protected override void OnAfterProperties(object value)
         {
+            _delayedValuesHelper.EndInit(value);
+
             base.OnAfterProperties(value);
 
             //AfterEndInit is not called as it supports only
             //Portable.Xaml.ComponentModel.ISupportInitialize
             //and we have Avalonia.ISupportInitialize so we need some hacks
-            _endEditValue = value;
+            HandleEndEdit(value);
+
+            _objects.Pop();
         }
 
         protected override void OnBeforeProperties(object value)
@@ -50,26 +57,49 @@ namespace Avalonia.Markup.Xaml.PortableXaml
             //OnAfterBeginInit is not called as it supports only
             //Portable.Xaml.ComponentModel.ISupportInitialize
             //and we have Avalonia.ISupportInitialize so we need some hacks
+
             HandleBeginInit(value);
 
+            _delayedValuesHelper.BeginInit(value);
+
             base.OnBeforeProperties(value);
-        }
 
-        public override void WriteEndObject()
-        {
-            base.WriteEndObject();
+            var target = Current;
 
-            //AfterEndInit is not called as it supports only
-            //Portable.Xaml.ComponentModel.ISupportInitialize
-            //and we have Avalonia.ISupportInitialize so we need some hacks
-            HandleEndEdit(_endEditValue);
-            _endEditValue = null;
-        }
+            var member = _lastStartMember;
+            _lastStartMember = null;
+
+            //if (target != null && value != null && member != null &&
+            //    member is PropertyXamlMember && !(value is MarkupExtension) &&
+            //    member.DeclaringType.ContentProperty?.Name == member.Name &&
+            //    !member.IsReadOnly &&
+            //    member.Invoker?.UnderlyingSetter != null)
+            //{
+            //    //set default content before start properties
+            //    try
+            //    {
+            //        if (!OnSetValue(target, member, value))
+            //        {
+            //            member.Invoker.SetValue(target, value);
+            //        }
+            //    }
+            //    catch (Exception ex)
+            //    {
+            //        throw new XamlObjectWriterException($"Set value of member '{member}' threw an exception", ex);
+            //    }
+            //}
 
-        private object _endEditValue;
+            _objects.Push(value);
+        }
 
         private AvaloniaNameScope _nameScope;
 
+        private Stack<object> _objects = new Stack<object>();
+
+        private object Current => _objects.Count > 0 ? _objects.Peek() : null;
+
+        private XamlMember _lastStartMember = null;
+
         private void HandleBeginInit(object value)
         {
             (value as Avalonia.ISupportInitialize)?.BeginInit();
@@ -82,7 +112,7 @@ namespace Avalonia.Markup.Xaml.PortableXaml
 
         private void HandleFinished()
         {
-            if(_nameScope != null &&  Result != null)
+            if (_nameScope != null && Result != null)
             {
                 _nameScope.RegisterOnNameScope(Result);
             }
@@ -97,5 +127,130 @@ namespace Avalonia.Markup.Xaml.PortableXaml
 
             base.Dispose(disposing);
         }
+
+        public override void WriteStartMember(XamlMember property)
+        {
+            base.WriteStartMember(property);
+
+            _lastStartMember = property;
+        }
+
+        public override void WriteEndMember()
+        {
+            base.WriteEndMember();
+
+            _lastStartMember = null;
+        }
+
+        protected override bool OnSetValue(object target, XamlMember member, object value)
+        {
+            if (value is IBinding)
+            {
+                //delay bindings
+                _delayedValuesHelper.Add(new DelayedValue(target, member, value));
+                return true;
+            }
+
+            return base.OnSetValue(target, member, value);
+        }
+
+        private readonly DelayedValuesHelper _delayedValuesHelper = new DelayedValuesHelper();
+
+        private class DelayedValue
+        {
+            public DelayedValue(object target, XamlMember member, object value)
+            {
+                Target = target;
+                Member = member;
+                Value = value;
+            }
+
+            public object Target { get; }
+
+            public XamlMember Member { get; }
+
+            public object Value { get; }
+        }
+
+        private class DelayedValuesHelper
+        {
+            private HashSet<object> _targets = new HashSet<object>();
+
+            private IList<DelayedValue> _values = new List<DelayedValue>();
+
+            private int cnt;
+
+            public void BeginInit(object target)
+            {
+                ++cnt;
+
+                AddTargetIfNeeded(target);
+            }
+
+            public void EndInit(object target)
+            {
+                --cnt;
+
+                if (cnt == 0)
+                {
+                    EndInit();
+                }
+                //else
+                //{
+                //    AddTargetIfNeeded(target);
+                //}
+            }
+
+            private void AddTargetIfNeeded(object target)
+            {
+                if (!_targets.Contains(target))
+                {
+                    Add(new DelayedValue(target, null, null));
+                }
+            }
+
+            public void Add(DelayedValue value)
+            {
+                _values.Add(value);
+
+                var target = value.Target;
+
+                if (!_targets.Contains(value.Target))
+                {
+                    _targets.Add(target);
+                    (target as ISupportInitialize)?.BeginInit();
+                }
+            }
+
+            private void EndInit()
+            {
+                //TODO: revisit this
+                //apply delayed values and clear
+                //that's the last object let's set all delayed bindings
+                foreach (var dv in Values.Reverse().Where(v => v.Member != null))
+                {
+                    dv.Member.Invoker.SetValue(dv.Target, dv.Value);
+                }
+
+                //TODO: check/add some order of end init
+                //currently we are sending end init in the order of
+                //objects creation
+                foreach (var v in Values.Reverse())
+                {
+                    var target = v.Target;
+
+                    if (_targets.Contains(target))
+                    {
+                        _targets.Remove(target);
+                        (target as ISupportInitialize)?.EndInit();
+                    }
+                }
+
+                _targets.Clear();
+                _values.Clear();
+            }
+
+            private IEnumerable<DelayedValue> Values => _values;
+        }
     }
 }

+ 61 - 16
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs

@@ -1,20 +1,20 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
+using Avalonia.Data;
 using Avalonia.Markup.Xaml.Context;
 using Portable.Xaml;
 using Portable.Xaml.ComponentModel;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
 using am = Avalonia.Metadata;
-using Avalonia.Data;
-using Avalonia.Markup.Xaml.Data;
 
 namespace Avalonia.Markup.Xaml.PortableXaml
 {
     internal class AvaloniaXamlSchemaContext : XamlSchemaContext
     {
         public AvaloniaXamlSchemaContext(IRuntimeTypeProvider typeProvider)
-            : base(typeProvider.ReferencedAssemblies)
+        //better not set the references assemblies
+        //: base(typeProvider.ReferencedAssemblies)
         {
             _avaloniaTypeProvider = typeProvider;
         }
@@ -64,7 +64,6 @@ namespace Avalonia.Markup.Xaml.PortableXaml
 
             if (type == null)
             {
-
                 //let's try the simple types
                 //in Portable xaml like xmlns:sys='clr-namespace:System;assembly=mscorlib'
                 //and sys:Double is not resolved properly
@@ -145,9 +144,9 @@ namespace Avalonia.Markup.Xaml.PortableXaml
 
         private XamlType GetAvaloniaXamlType(Type type)
         {
-            if (type == typeof(Binding))
+            if (typeof(IBinding).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))
             {
-                return new BindingXamlType(type, this);
+                return BindingXamlType.Create(type, this);
             }
 
             //TODO: do we need it ???
@@ -161,7 +160,33 @@ namespace Avalonia.Markup.Xaml.PortableXaml
 
         protected override XamlMember GetAttachableProperty(string attachablePropertyName, MethodInfo getter, MethodInfo setter)
         {
-            return base.GetAttachableProperty(attachablePropertyName, getter, setter);
+            var key = new Tuple<MemberInfo, MemberInfo>(getter, setter);
+
+            XamlMember result;
+
+            if (_cachedMembers.TryGetValue(key, out result))
+            {
+                return result;
+            }
+
+            var type = (getter ?? setter).DeclaringType;
+
+            var prop = AvaloniaPropertyRegistry.Instance.GetAttached(type)
+                    .FirstOrDefault(v => v.Name == attachablePropertyName);
+
+            if (prop != null)
+            {
+                result = new AvaloniaAttachedPropertyXamlMember(
+                                        prop, attachablePropertyName,
+                                        getter, setter, this);
+            }
+
+            if (result == null)
+            {
+                result = base.GetAttachableProperty(attachablePropertyName, getter, setter);
+            }
+
+            return _cachedMembers[key] = result;
         }
 
         protected override XamlMember GetProperty(PropertyInfo pi)
@@ -169,28 +194,48 @@ namespace Avalonia.Markup.Xaml.PortableXaml
             Type objType = pi.DeclaringType;
             string name = pi.Name;
 
+            XamlMember result;
+
+            var key = new Tuple<MemberInfo, MemberInfo>(pi, null);
+
+            if (_cachedMembers.TryGetValue(key, out result))
+            {
+                return result;
+            }
+
             var avProp = AvaloniaPropertyRegistry.Instance.FindRegistered(objType, name);
 
             var assignBindingAttr = pi.GetCustomAttribute<AssignBindingAttribute>();
 
             if (avProp != null)
             {
-                return new AvaloniaPropertyXamlMember(avProp, pi, this)
+                result = new AvaloniaPropertyXamlMember(avProp, pi, this)
                 {
                     AssignBinding = assignBindingAttr != null
                 };
             }
 
-            var dependAttr = pi.GetCustomAttribute<am.DependsOnAttribute>();
+            if (result == null)
+            {
+                var dependAttr = pi.GetCustomAttribute<am.DependsOnAttribute>();
+
+                if (dependAttr != null)
+                {
+                    result = new DependOnXamlMember(dependAttr.Name, pi, this);
+                }
+            }
 
-            if (dependAttr != null)
+            if (result == null)
             {
-                return new DependOnXamlMember(dependAttr.Name, pi, this);
+                result = new PropertyXamlMember(pi, this);
             }
 
-            return base.GetProperty(pi);
+            return _cachedMembers[key] = result;
         }
 
         private Dictionary<Type, XamlType> _cachedTypes = new Dictionary<Type, XamlType>();
+
+        private Dictionary<Tuple<MemberInfo, MemberInfo>, XamlMember> _cachedMembers =
+                        new Dictionary<Tuple<MemberInfo, MemberInfo>, XamlMember>();
     }
 }

+ 140 - 13
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs

@@ -1,10 +1,14 @@
-using System;
-using System.Collections.Generic;
-using System.Reflection;
+using Avalonia.Controls;
 using Avalonia.Data;
+using Avalonia.Markup.Xaml.Data;
+using Avalonia.Markup.Xaml.MarkupExtensions;
 using Portable.Xaml;
-using Portable.Xaml.Markup;
+using Portable.Xaml.ComponentModel;
 using Portable.Xaml.Schema;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Xml.Serialization;
 
 namespace Avalonia.Markup.Xaml.PortableXaml
 {
@@ -18,23 +22,95 @@ namespace Avalonia.Markup.Xaml.PortableXaml
 
     public class BindingXamlType : AvaloniaXamlType
     {
-        public BindingXamlType(Type underlyingType, XamlSchemaContext schemaContext) :
+        public static BindingXamlType Create(Type type, XamlSchemaContext schemaContext)
+        {
+            if (type == typeof(Binding))
+            {
+                //in xmal we need to use the extension
+                type = typeof(BindingExtension);
+            }
+
+            return new BindingXamlType(type, schemaContext);
+        }
+
+        private static HashSet<Type> _notAssignable =
+        new HashSet<Type>()
+        {
+            typeof (IXmlSerializable)
+        };
+
+        private BindingXamlType(Type underlyingType, XamlSchemaContext schemaContext) :
             base(underlyingType, schemaContext)
         {
         }
 
         public override bool CanAssignTo(XamlType xamlType)
         {
+            if (_notAssignable.Contains(xamlType.UnderlyingType))
+            {
+                return false;
+            }
+
             return true;
         }
+
+        protected override XamlMember LookupAliasedProperty(XamlDirective directive)
+        {
+            return base.LookupAliasedProperty(directive);
+        }
+
+        protected override bool LookupIsMarkupExtension()
+        {
+            return base.LookupIsMarkupExtension();
+        }
     }
 
-    public class AvaloniaPropertyXamlMember : XamlMember
+    public class PropertyXamlMember : XamlMember
+    {
+        protected PropertyXamlMember(string attachablePropertyName,
+            MethodInfo getter, MethodInfo setter, XamlSchemaContext schemaContext)
+            : base(attachablePropertyName, getter, setter, schemaContext)
+        {
+        }
+
+        public PropertyXamlMember(
+                PropertyInfo propertyInfo,
+                XamlSchemaContext schemaContext) :
+            base(propertyInfo, schemaContext)
+        {
+        }
+
+        protected override MethodInfo LookupUnderlyingSetter()
+        {
+            //if we have content property a list
+            //we have some issues in portable.xaml
+            //but if the list is read only, this is solving the problem
+            //TODO: investigate is this good enough as solution ???
+            //We can add ReadOnyAttribute to cover this
+            if ((Type.IsCollection || Type.IsDictionary) &&
+                 Name == DeclaringType.ContentProperty?.Name)
+            {
+                return null;
+            }
+
+            return base.LookupUnderlyingSetter();
+        }
+    }
+
+    public class AvaloniaPropertyXamlMember : PropertyXamlMember
     {
         public bool AssignBinding { get; set; } = false;
 
         public AvaloniaProperty Property { get; }
 
+        protected AvaloniaPropertyXamlMember(AvaloniaProperty property,
+            string attachablePropertyName,
+            MethodInfo getter, MethodInfo setter, XamlSchemaContext schemaContext)
+            : base(attachablePropertyName, getter, setter, schemaContext)
+        {
+            Property = property;
+        }
+
         public AvaloniaPropertyXamlMember(AvaloniaProperty property,
                         PropertyInfo propertyInfo,
                         XamlSchemaContext schemaContext) :
@@ -48,6 +124,16 @@ namespace Avalonia.Markup.Xaml.PortableXaml
             return new AvaloniaPropertyInvoker(this);
         }
 
+        protected override bool LookupIsReadOnly()
+        {
+            if (Property.IsReadOnly)
+            {
+                return true;
+            }
+
+            return base.LookupIsReadOnly();
+        }
+
         private class AvaloniaPropertyInvoker : XamlMemberInvoker
         {
             public AvaloniaPropertyInvoker(XamlMember member) : base(member)
@@ -59,9 +145,14 @@ namespace Avalonia.Markup.Xaml.PortableXaml
                 if (Property != null)
                 {
                     var obj = ((IAvaloniaObject)instance);
-                    if (value is IBinding && !Member.AssignBinding)
+                    if (value is IBinding)
                     {
-                        ApplyBinding(obj, (IBinding)value);
+                        if (!Member.AssignBinding)
+                            ApplyBinding(obj, (IBinding)value);
+                        else
+                            obj.SetValue(Property, value is XamlBinding ?
+                                                        (value as XamlBinding).Value :
+                                                        value);
                     }
                     else
                     {
@@ -86,11 +177,23 @@ namespace Avalonia.Markup.Xaml.PortableXaml
                 }
             }
 
-            private void ApplyBinding(IAvaloniaObject obj, IBinding binding)
+            public void ApplyBinding(IAvaloniaObject obj, IBinding binding)
             {
-                //TODO: in Context.PropertyAccessor there is
-                //some quirk stuff check it later
-                obj.Bind(Property, binding);
+                var control = obj as IControl;
+                var property = Property;
+                var xamlBinding = binding as XamlBinding;
+                //if (control != null && property != Control.DataContextProperty)
+                //    DelayedBinding.Add(control, property, binding);
+                //else
+                if (xamlBinding != null)
+                    obj.Bind(property, xamlBinding.Value, xamlBinding.Anchor?.Target);
+                else
+                    obj.Bind(property, binding);
+            }
+
+            public void SetValue(ITypeDescriptorContext context, object instance, object value)
+            {
+                throw new NotImplementedException();
             }
 
             private AvaloniaProperty Property => Member.Property;
@@ -100,7 +203,27 @@ namespace Avalonia.Markup.Xaml.PortableXaml
         }
     }
 
-    public class DependOnXamlMember : XamlMember
+    public class AvaloniaAttachedPropertyXamlMember : AvaloniaPropertyXamlMember
+    {
+        private MethodInfo _setter;
+
+        public AvaloniaAttachedPropertyXamlMember(AvaloniaProperty property,
+                                                    string attachablePropertyName,
+                                                    MethodInfo getter, MethodInfo setter, 
+                                                    XamlSchemaContext schemaContext)
+            : base(property, attachablePropertyName, getter, setter, schemaContext)
+        {
+            _setter = setter;
+        }
+
+        protected override MethodInfo LookupUnderlyingSetter()
+        {
+            //TODO: investigate don't call base stack overflow
+            return _setter;
+        }
+    }
+
+    public class DependOnXamlMember : PropertyXamlMember
     {
         private string _dependOn;
 
@@ -157,6 +280,10 @@ namespace Avalonia.Markup.Xaml.PortableXaml
                         value = ttConv.ConvertFromString(value as string);
                     }
                 }
+                if (value is XamlBinding)
+                {
+                    value = (value as XamlBinding).Value;
+                }
 
                 base.SetValue(instance, value);
             }

+ 23 - 0
src/Markup/Avalonia.Markup.Xaml/PortableXaml/TypeDescriptorExtensions.cs

@@ -1,5 +1,7 @@
 using System;
 using Portable.Xaml.Markup;
+using System.Linq;
+using System.Collections.Generic;
 
 namespace Portable.Xaml.ComponentModel
 {
@@ -33,5 +35,26 @@ namespace Portable.Xaml.ComponentModel
 
             return tr?.Resolve(name);
         }
+
+        public static T GetFirstAmbientValue<T>(this ITypeDescriptorContext ctx) where T : class
+        {
+            var amb = ctx.GetService<IAmbientProvider>();
+            var sc = ctx.GetService<IXamlSchemaContextProvider>().SchemaContext;
+
+            return amb.GetFirstAmbientValue(sc.GetXamlType(typeof(T))) as T;
+        }
+
+        public static T GetLastOrDefaultAmbientValue<T>(this ITypeDescriptorContext ctx) where T : class
+        {
+            return ctx.GetAllambientValues<T>().LastOrDefault() as T;
+        }
+
+        public static IEnumerable<T> GetAllambientValues<T>(this ITypeDescriptorContext ctx) where T : class
+        {
+            var amb = ctx.GetService<IAmbientProvider>();
+            var sc = ctx.GetService<IXamlSchemaContextProvider>().SchemaContext;
+
+            return amb.GetAllAmbientValues(sc.GetXamlType(typeof(T))).OfType<T>();
+        }
     }
 }

+ 68 - 0
src/Markup/Avalonia.Markup.Xaml/PortableXaml/XamlBinding.cs

@@ -0,0 +1,68 @@
+using Avalonia.Controls;
+using Avalonia.Data;
+using Avalonia.Styling;
+using Portable.Xaml.ComponentModel;
+using Portable.Xaml.Markup;
+using System;
+
+namespace Avalonia.Markup.Xaml.PortableXaml
+{
+    internal class XamlBinding : IBinding
+    {
+        public static IBinding FromMarkupExtensionContext(
+                                    IBinding binding,
+                                    IServiceProvider serviceProvider)
+        {
+            var context = (ITypeDescriptorContext)serviceProvider;
+            var pvt = context.GetService<IProvideValueTarget>();
+
+            if (pvt.TargetObject is IControl) return binding;
+
+            object anchor = GetDefaultAnchor(context);
+
+            if (anchor == null) return binding;
+
+            return new XamlBinding(binding, anchor);
+        }
+
+        private static object GetDefaultAnchor(ITypeDescriptorContext context)
+        {
+            object anchor = null;
+
+            //// The target is not a control, so we need to find an anchor that will let us look
+            //// up named controls and style resources. First look for the closest IControl in
+            //// the TopDownValueContext.
+
+            //anchor = context.TopDownValueContext.StoredInstances
+            //    .Select(x => x.Instance)
+            //    .OfType<IControl>()
+            //    .LastOrDefault();
+            anchor = context.GetFirstAmbientValue<IControl>();
+
+            //// If a control was not found, then try to find the highest-level style as the XAML
+            //// file could be a XAML file containing only styles.
+            //    anchor = context.TopDownValueContext.StoredInstances
+            //        .Select(x => x.Instance)
+            //        .OfType<IStyle>()
+            //        .FirstOrDefault();
+            return anchor ?? context.GetLastOrDefaultAmbientValue<IStyle>();
+        }
+
+        private XamlBinding(IBinding binding, object anchor)
+        {
+            Value = binding;
+
+            Anchor = new WeakReference(anchor);
+        }
+
+        public WeakReference Anchor { get; }
+
+        public IBinding Value { get; }
+
+        public InstancedBinding Initiate(IAvaloniaObject target, AvaloniaProperty targetProperty, object anchor = null, bool enableDataValidation = false)
+        {
+            return Value.Initiate(target, targetProperty,
+                            anchor ?? Anchor.Target, enableDataValidation);
+        }
+    }
+}