From d55a2b2227df331b0d7f11c0adeaa5233a9d23ae Mon Sep 17 00:00:00 2001 From: donandren Date: Fri, 3 Mar 2017 15:49:13 +0200 Subject: [PATCH] template binding and xaml extensions operational --- .../AvaloniaXamlLoaderPortableXaml.cs | 11 ++- .../MarkupExtensions/BindingExtension.cs | 55 +++++++++++- .../RelativeSourceExtension.cs | 35 +++++++- .../Standard/StaticExtension.cs | 2 + .../Standard/TypeExtension.cs | 2 + .../MarkupExtensions/StaticExtension.cs | 16 +++- .../StyleResourceExtension.cs | 29 ++++++- .../TemplateBindingExtension.cs | 50 ++++++++++- .../MarkupExtensions/TypeExtension.cs | 24 ++++-- .../PortableXaml/AvaloniaXamlSchemaContext.cs | 47 ++++++++++- .../PortableXaml/AvaloniaXamlType.cs | 83 ++++++++++++++++--- 11 files changed, 325 insertions(+), 29 deletions(-) diff --git a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs index 3edb6361c1..aac2951deb 100644 --- a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs +++ b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs @@ -195,13 +195,18 @@ namespace Avalonia.Markup.Xaml } } - internal static object LoadFromReader(XamlReader reader, object instance = null) + internal static object LoadFromReader(XamlReader reader, object instance) { var writer = AvaloniaXamlObjectWriter.Create(_context, 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); } /// diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs index b131f07fd4..6498ca1521 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs @@ -1,12 +1,64 @@ // 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 OmniXaml; using Avalonia.Data; using Avalonia.Markup.Xaml.Data; +using System; namespace Avalonia.Markup.Xaml.MarkupExtensions { + +#if !OMNIXAML + + using Portable.Xaml.Markup; + + [MarkupExtensionReturnType(typeof(Binding))] + public class BindingExtension : MarkupExtension + { + public BindingExtension() + { + } + + public BindingExtension(string path) + { + Path = path; + } + + public override object ProvideValue(IServiceProvider serviceProvider) + { + return new Binding + { + Converter = Converter, + ConverterParameter = ConverterParameter, + ElementName = ElementName, + FallbackValue = FallbackValue, + Mode = Mode, + Path = Path, + Priority = Priority, + }; + } + + public IValueConverter Converter { get; set; } + + public object ConverterParameter { get; set; } + + public string ElementName { get; set; } + + public object FallbackValue { get; set; } = AvaloniaProperty.UnsetValue; + + public BindingMode Mode { get; set; } + + [ConstructorArgument("path")] + public string Path { get; set; } + + public BindingPriority Priority { get; set; } = BindingPriority.LocalValue; + + public object Source { get; set; } + } +#else + + using OmniXaml; + public class BindingExtension : MarkupExtension { public BindingExtension() @@ -41,4 +93,5 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions public BindingPriority Priority { get; set; } = BindingPriority.LocalValue; public object Source { get; set; } } +#endif } \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs index 1120494dfa..b5e4a73a8a 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs @@ -1,11 +1,43 @@ // 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 OmniXaml; + using Avalonia.Markup.Xaml.Data; + namespace Avalonia.Markup.Xaml.MarkupExtensions { +#if !OMNIXAML + + using System; + using Portable.Xaml.Markup; + + public class RelativeSourceExtension : MarkupExtension + { + public RelativeSourceExtension() + { + } + + public RelativeSourceExtension(RelativeSourceMode mode) + { + Mode = mode; + } + + public override object ProvideValue(IServiceProvider serviceProvider) + { + return new RelativeSource + { + Mode = Mode, + }; + } + + [ConstructorArgument("mode")] + public RelativeSourceMode Mode { get; set; } + } +#else + + using OmniXaml; + public class RelativeSourceExtension : MarkupExtension { public RelativeSourceExtension() @@ -27,4 +59,5 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions public RelativeSourceMode Mode { get; set; } } +#endif } \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/Standard/StaticExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/Standard/StaticExtension.cs index fd99892699..6d1945dabd 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/Standard/StaticExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/Standard/StaticExtension.cs @@ -9,6 +9,7 @@ using Glass.Core; namespace Avalonia.Markup.Xaml.MarkupExtensions.Standard { +#if OMNIXAML public class StaticExtension : MarkupExtension { public StaticExtension() @@ -83,4 +84,5 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.Standard throw new ArgumentException($"Static member '{type}.{name}' not found."); } } +#endif } \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/Standard/TypeExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/Standard/TypeExtension.cs index 11b390365c..705081e34a 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/Standard/TypeExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/Standard/TypeExtension.cs @@ -9,6 +9,7 @@ using Glass.Core; namespace Avalonia.Markup.Xaml.MarkupExtensions.Standard { +#if OMNIXAML [ContentProperty("TargetType")] public class TypeExtension : MarkupExtension { @@ -46,4 +47,5 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.Standard return ResolveFromString(TypeName, markupExtensionContext.ValueContext.TypeRepository); } } +#endif } \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticExtension.cs index 051862a167..c54ea90add 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticExtension.cs @@ -4,11 +4,22 @@ using System; using System.Linq; using System.Reflection; -using OmniXaml; -using Glass.Core; + namespace Avalonia.Markup.Xaml.MarkupExtensions { +#if !OMNIXAML + + //TODO: check do we need something more than std Portable.xaml static?? + public class StaticExtension : Portable.Xaml.Markup.StaticExtension + { + + } + +#else + using OmniXaml; + using Glass.Core; + public class StaticExtension : MarkupExtension { public StaticExtension() @@ -83,4 +94,5 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions throw new ArgumentException($"Static member '{type}.{name}' not found."); } } +#endif } \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs index 9b1c520bf0..ed98fbb523 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs @@ -3,13 +3,39 @@ using System; using System.Reactive.Linq; -using OmniXaml; + using Avalonia.LogicalTree; using Avalonia.Markup.Xaml.Data; using Avalonia.Styling; + namespace Avalonia.Markup.Xaml.MarkupExtensions { +#if !OMNIXAML + + using Portable.Xaml.Markup; + + [MarkupExtensionReturnType(typeof(StyleResourceBinding))] + public class StyleResourceExtension : MarkupExtension + { + public StyleResourceExtension(string name) + { + Name = name; + } + + public override object ProvideValue(IServiceProvider serviceProvider) + { + return new StyleResourceBinding(this.Name); + } + + [ConstructorArgument("name")] + public string Name { get; set; } + } + +#else + + using OmniXaml; + public class StyleResourceExtension : MarkupExtension { public StyleResourceExtension(string name) @@ -24,4 +50,5 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions public string Name { get; set; } } +#endif } \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs index 3c4faac3a8..b9649c8a5b 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs @@ -1,12 +1,59 @@ // 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 OmniXaml; using Avalonia.Data; using Avalonia.Markup.Xaml.Data; namespace Avalonia.Markup.Xaml.MarkupExtensions { +#if !OMNIXAML + + using System; + using Portable.Xaml.Markup; + + [MarkupExtensionReturnType(typeof(Binding))] + public class TemplateBindingExtension : MarkupExtension + { + public TemplateBindingExtension() + { + } + + public TemplateBindingExtension(string path) + { + Path = path; + } + + public override object ProvideValue(IServiceProvider serviceProvider) + { + return new Binding + { + Converter = Converter, + ElementName = ElementName, + Mode = Mode, + RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent), + Path = Path, + Priority = Priority, + }; + } + + public IValueConverter Converter { get; set; } + + public string ElementName { get; set; } + + public object FallbackValue { get; set; } + + public BindingMode Mode { get; set; } + + [ConstructorArgument("path")] + public string Path { get; set; } + + public BindingPriority Priority { get; set; } = BindingPriority.TemplatedParent; + } + +#else + + using OmniXaml; + public class TemplateBindingExtension : MarkupExtension { public TemplateBindingExtension() @@ -38,4 +85,5 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions public string Path { get; set; } public BindingPriority Priority { get; set; } = BindingPriority.TemplatedParent; } +#endif } \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TypeExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TypeExtension.cs index 3a6f946f3a..38473ae975 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TypeExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TypeExtension.cs @@ -1,14 +1,24 @@ // 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 OmniXaml; -using OmniXaml.Attributes; -using OmniXaml.Typing; -using Glass.Core; - namespace Avalonia.Markup.Xaml.MarkupExtensions { +#if !OMNIXAML + + //TODO: check do we need something more than std Portable.xaml type?? + public class TypeExtension : Portable.Xaml.Markup.TypeExtension + { + + } + +#else + + using System; + using OmniXaml; + using OmniXaml.Attributes; + using OmniXaml.Typing; + using Glass.Core; + [ContentProperty("TargetType")] public class TypeExtension : MarkupExtension { @@ -46,4 +56,6 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions return ResolveFromString(TypeName, markupExtensionContext.ValueContext.TypeRepository); } } + +#endif } \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs index 9b08d726dc..d1b8fda7a2 100644 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs +++ b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs @@ -5,6 +5,8 @@ using System.Reflection; using Avalonia.Markup.Xaml.Context; using Portable.Xaml; using Portable.Xaml.ComponentModel; +using am = Avalonia.Metadata; +using Avalonia.Data; namespace Avalonia.Markup.Xaml.PortableXaml { @@ -51,10 +53,15 @@ namespace Avalonia.Markup.Xaml.PortableXaml } } - Type type = _avaloniaTypeProvider.FindType(xmlNamespace, xmlLocalName, genArgs); + // MarkupExtension type could omit "Extension" part in XML name. + Type type = _avaloniaTypeProvider.FindType(xmlNamespace, xmlLocalName, genArgs) + ?? _avaloniaTypeProvider.FindType(xmlNamespace, + xmlLocalName + "Extension", + genArgs); if (type == null) { + //let's try the simple types //in Portable xaml xmlns:sys='clr-namespace:System;assembly=mscorlib' //and sys:Double is not resolved @@ -118,12 +125,44 @@ namespace Avalonia.Markup.Xaml.PortableXaml public override XamlType GetXamlType(Type type) { - if (type.FullName.StartsWith("Avalonia.")) + //if (type.FullName.StartsWith("Avalonia.")) + //{ + // return new AvaloniaXamlType(type, this); + //} + return base.GetXamlType(type); + } + + + protected override XamlMember GetAttachableProperty(string attachablePropertyName, MethodInfo getter, MethodInfo setter) + { + return base.GetAttachableProperty(attachablePropertyName, getter, setter); + } + + protected override XamlMember GetProperty(PropertyInfo pi) + { + Type objType = pi.DeclaringType; + string name = pi.Name; + + var avProp = AvaloniaPropertyRegistry.Instance.FindRegistered(objType, name); + + var assignBindingAttr = pi.GetCustomAttribute(); + + if (avProp != null) { - return new AvaloniaXamlType(type, this); + return new AvaloniaPropertyXamlMember(avProp, pi, this) + { + AssignBinding = assignBindingAttr != null + }; } - return base.GetXamlType(type); + var dependAttr = pi.GetCustomAttribute(); + + if (dependAttr != null) + { + return new DependOnXamlMember(dependAttr.Name, pi, this); + } + + return base.GetProperty(pi); } } } \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs index ee1acbefa7..350d56471c 100644 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs +++ b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs @@ -1,31 +1,94 @@ using System; using System.Collections.Generic; using System.Reflection; +using Avalonia.Data; using Portable.Xaml; using Portable.Xaml.Schema; -using am = Avalonia.Metadata; + namespace Avalonia.Markup.Xaml.PortableXaml { - public class AvaloniaXamlType : XamlType + //public class AvaloniaXamlType : XamlType + //{ + // public AvaloniaXamlType(Type underlyingType, XamlSchemaContext schemaContext) : + // base(underlyingType, schemaContext) + // { + // } + + // protected override XamlMember LookupMember(string name, bool skipReadOnlyCheck) + // { + // return base.LookupMember(name, skipReadOnlyCheck); + // } + //} + + public class AvaloniaPropertyXamlMember : XamlMember { - public AvaloniaXamlType(Type underlyingType, XamlSchemaContext schemaContext) : - base(underlyingType, schemaContext) + public bool AssignBinding { get; set; } = false; + + public AvaloniaProperty Property { get; } + + public AvaloniaPropertyXamlMember(AvaloniaProperty property, + PropertyInfo propertyInfo, + XamlSchemaContext schemaContext) : + base(propertyInfo, schemaContext) { + Property = property; } - protected override XamlMember LookupMember(string name, bool skipReadOnlyCheck) + protected override XamlMemberInvoker LookupInvoker() { - var pi = UnderlyingType.GetRuntimeProperty(name); + return new AvaloniaPropertyInvoker(this); + } - var dependAttr = pi.GetCustomAttribute(); + private class AvaloniaPropertyInvoker : XamlMemberInvoker + { + public AvaloniaPropertyInvoker(XamlMember member) : base(member) + { + } - if (dependAttr != null) + public override void SetValue(object instance, object value) { - return new DependOnXamlMember(dependAttr.Name, pi, SchemaContext); + if (Property != null) + { + var obj = ((IAvaloniaObject)instance); + if (value is IBinding && !Member.AssignBinding) + { + ApplyBinding(obj, (IBinding)value); + } + else + { + obj.SetValue(Property, value); + } + } + else + { + base.SetValue(instance, value); + } + } + + public override object GetValue(object instance) + { + if (Property != null) + { + return ((IAvaloniaObject)instance).GetValue(Property); + } + else + { + return base.GetValue(instance); + } } - return base.LookupMember(name, skipReadOnlyCheck); + private void ApplyBinding(IAvaloniaObject obj, IBinding binding) + { + //TODO: in Context.PropertyAccessor there is + //some quirk stuff check it later + obj.Bind(Property, binding); + } + + private AvaloniaProperty Property => Member.Property; + + private new AvaloniaPropertyXamlMember Member => + (AvaloniaPropertyXamlMember)base.Member; } }