diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
index 2f33fb912d..6cc354bc00 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
+++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
@@ -44,6 +44,7 @@
+
@@ -274,6 +275,8 @@
+
+
diff --git a/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaRuntimeTypeSource.cs b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaRuntimeTypeSource.cs
index 762ffdb24b..dfc8fbceee 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaRuntimeTypeSource.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaRuntimeTypeSource.cs
@@ -1,5 +1,6 @@
namespace Avalonia.Markup.Xaml.Context
{
+#if OMNIXAML
using System;
using System.Collections.Generic;
using System.Linq;
@@ -88,4 +89,5 @@ namespace Avalonia.Markup.Xaml.Context
return inner.GetAttachableMember(name, getter, setter);
}
}
+#endif
}
\ No newline at end of file
diff --git a/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaTypeFeatureProvider.cs b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaTypeFeatureProvider.cs
index 7828934a62..d03fd2e72c 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaTypeFeatureProvider.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaTypeFeatureProvider.cs
@@ -23,6 +23,7 @@ using OmniMetadata = OmniXaml.Typing.Metadata;
namespace Avalonia.Markup.Xaml.Context
{
+#if OMNIXAML
public class AvaloniaTypeFeatureProvider : ITypeFeatureProvider
{
private Dictionary _metadata =
@@ -177,4 +178,5 @@ namespace Avalonia.Markup.Xaml.Context
RegisterTypeConverter(typeof(FontWeight), new FontWeightConverter());
}
}
+#endif
}
\ No newline at end of file
diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs
index 026217eacb..ae9339b299 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs
@@ -4,12 +4,99 @@
using System;
using System.Globalization;
using System.Linq;
-using OmniXaml;
-using OmniXaml.TypeConversion;
-using Avalonia.Styling;
namespace Avalonia.Markup.Xaml.Converters
{
+ using Avalonia.Styling;
+ using Portable.Xaml;
+#if !OMNIXAML
+
+ using Portable.Xaml.ComponentModel;
+ using Portable.Xaml.Markup;
+
+ public class AvaloniaPropertyTypeConverter : TypeConverter
+ {
+ public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
+ {
+ return sourceType == typeof(string);
+ }
+
+ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
+ {
+ var s = (string)value;
+
+ string typeName;
+ string propertyName;
+ Type type = null;
+
+ ParseProperty(s, out typeName, out propertyName);
+
+ if (typeName == null)
+ {
+ var amb = context.GetService();
+ var sc = context.GetService().SchemaContext;
+ var xamlStyleType = sc.GetXamlType(typeof(Style));
+ var ambValue = amb.GetFirstAmbientValue(xamlStyleType) as AmbientPropertyValue;
+
+ var style = ambValue?.Value as Style;
+ type = style.Selector?.TargetType;
+
+ if (type == null)
+ {
+ throw new Exception(
+ "Could not determine the target type. Please fully qualify the property name.");
+ }
+ }
+ else
+ {
+ //type = context.TypeRepository.GetByQualifiedName(typeName)?.UnderlyingType;
+
+ if (type == null)
+ {
+ throw new Exception($"Could not find type '{typeName}'.");
+ }
+ }
+
+ // First look for non-attached property on the type and then look for an attached property.
+ var property = AvaloniaPropertyRegistry.Instance.FindRegistered(type, s) ??
+ AvaloniaPropertyRegistry.Instance.GetAttached(type)
+ .FirstOrDefault(x => x.Name == propertyName);
+
+ if (property == null)
+ {
+ throw new Exception(
+ $"Could not find AvaloniaProperty '{type.Name}.{propertyName}'.");
+ }
+
+ return property;
+ }
+
+ private void ParseProperty(string s, out string typeName, out string propertyName)
+ {
+ var split = s.Split('.');
+
+ if (split.Length == 1)
+ {
+ typeName = null;
+ propertyName = split[0];
+ }
+ else if (split.Length == 2)
+ {
+ typeName = split[0];
+ propertyName = split[1];
+ }
+ else
+ {
+ throw new Exception($"Invalid property name: '{s}'.");
+ }
+ }
+ }
+
+#else
+
+ using OmniXaml;
+ using OmniXaml.TypeConversion;
+
public class AvaloniaPropertyTypeConverter : ITypeConverter
{
public bool CanConvertFrom(IValueContext context, Type sourceType)
@@ -93,4 +180,5 @@ namespace Avalonia.Markup.Xaml.Converters
}
}
}
+#endif
}
\ No newline at end of file
diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/BrushTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/BrushTypeConverter.cs
index 45f835914f..0c256cf645 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Converters/BrushTypeConverter.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/Converters/BrushTypeConverter.cs
@@ -3,11 +3,32 @@
using System;
using System.Globalization;
-using OmniXaml.TypeConversion;
+
using Avalonia.Media;
namespace Avalonia.Markup.Xaml.Converters
{
+#if !OMNIXAML
+
+ using Portable.Xaml.ComponentModel;
+
+ public class BrushTypeConverter : TypeConverter
+ {
+ public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
+ {
+ return sourceType == typeof(string);
+ }
+
+ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
+ {
+ return Brush.Parse((string)value);
+ }
+ }
+
+#else
+
+ using OmniXaml.TypeConversion;
+
public class BrushTypeConverter : ITypeConverter
{
public bool CanConvertFrom(IValueContext context, Type sourceType)
@@ -30,4 +51,5 @@ namespace Avalonia.Markup.Xaml.Converters
throw new NotImplementedException();
}
}
+#endif
}
\ No newline at end of file
diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/SelectorTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/SelectorTypeConverter.cs
index 0970f42724..391663ed43 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Converters/SelectorTypeConverter.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/Converters/SelectorTypeConverter.cs
@@ -3,11 +3,33 @@
using System;
using System.Globalization;
-using OmniXaml.TypeConversion;
using Avalonia.Markup.Xaml.Parsers;
namespace Avalonia.Markup.Xaml.Converters
{
+#if !OMNIXAML
+
+ using Portable.Xaml.ComponentModel;
+
+ public class SelectorTypeConverter : TypeConverter
+ {
+ public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
+ {
+ return sourceType == typeof(string);
+ }
+
+ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
+ {
+ var parser = new SelectorParser((t, ns) => context.ResolveType(ns, t));
+
+ return parser.Parse((string)value);
+ }
+ }
+
+#else
+
+ using OmniXaml.TypeConversion;
+
public class SelectorTypeConverter : ITypeConverter
{
public bool CanConvertFrom(IValueContext context, Type sourceType)
@@ -31,4 +53,6 @@ namespace Avalonia.Markup.Xaml.Converters
throw new NotImplementedException();
}
}
+
+#endif
}
\ No newline at end of file
diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaDefaultTypeConverters.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaDefaultTypeConverters.cs
new file mode 100644
index 0000000000..e92b84b041
--- /dev/null
+++ b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaDefaultTypeConverters.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using Avalonia.Markup.Xaml.Converters;
+using Avalonia.Media;
+using Avalonia.Media.Imaging;
+using Avalonia.Styling;
+
+namespace Avalonia.Markup.Xaml.PortableXaml
+{
+ public class AvaloniaDefaultTypeConverters
+ {
+ private static Dictionary _defaultConverters = new Dictionary()
+ {
+ { typeof(IBitmap), typeof(BitmapTypeConverter)},
+ { typeof(IBrush), typeof(BrushTypeConverter) },
+ //{ typeof(Color), typeof(ColorTypeConverter) },
+ //{ typeof(Classes), typeof(ClassesTypeConverter) },
+ //{ typeof(ColumnDefinitions), typeof(ColumnDefinitionsTypeConverter) },
+ //{ typeof(DateTime), typeof(DateTimeTypeConverter) },
+ //{ typeof(Geometry), typeof(GeometryTypeConverter) },
+ //{ typeof(GridLength), typeof(GridLengthTypeConverter) },
+ //{ typeof(KeyGesture), typeof(KeyGestureConverter) },
+ //{ typeof(AvaloniaList), typeof(AvaloniaListTypeConverter) },
+ //{ typeof(IMemberSelector), typeof(MemberSelectorTypeConverter) },
+ //{ typeof(Point), typeof(PointTypeConverter) },
+ //{ typeof(IList), typeof(PointsListTypeConverter) },
+ { typeof(AvaloniaProperty), typeof(AvaloniaPropertyTypeConverter) },
+ //{ typeof(RelativePoint), typeof(RelativePointTypeConverter) },
+ //{ typeof(RelativeRect), typeof(RelativeRectTypeConverter) },
+ //{ typeof(RowDefinitions), typeof(RowDefinitionsTypeConverter) },
+ //{ typeof(Size), typeof(SizeTypeConverter) },
+ { typeof(Selector), typeof(SelectorTypeConverter)},
+ //{ typeof(SolidColorBrush), typeof(BrushTypeConverter) },
+ //{ typeof(Thickness), typeof(ThicknessTypeConverter) },
+ //{ typeof(TimeSpan), typeof(TimeSpanTypeConverter) },
+ //{ typeof(Uri), typeof(Converters.UriTypeConverter) },
+ //{ typeof(Cursor), typeof(CursorTypeConverter) },
+ //{ typeof(WindowIcon), typeof(IconTypeConverter) },
+ //{ typeof(FontWeight), typeof(FontWeightConverter) },
+ };
+
+ public static Type GetTypeConverter(Type type)
+ {
+ Type converterType;
+
+ Type curType = type;
+
+ while (curType != null)
+ {
+ if (_defaultConverters.TryGetValue(curType, out converterType))
+ {
+ if (curType != type)
+ {
+ _defaultConverters[curType] = converterType;
+ }
+
+ return converterType;
+ }
+ else
+ {
+ _defaultConverters[curType] = null;
+ }
+
+ curType = curType.GetTypeInfo().BaseType;
+ }
+
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs
index ba470d521d..1604fadf4b 100644
--- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs
@@ -43,6 +43,25 @@ namespace Avalonia.Markup.Xaml.PortableXaml
};
}
}
+ else if (attributeType == typeof(TypeConverterAttribute))
+ {
+ var attribs = _type.GetTypeInfo().GetCustomAttributes(attributeType, inherit);
+
+ if (attribs?.Any() != true)
+ {
+ var convType = AvaloniaDefaultTypeConverters.GetTypeConverter(_type);
+
+ if (convType != null)
+ {
+ return new object[]
+ {
+ new TypeConverterAttribute(convType)
+ };
+ }
+ }
+
+ return (attribs as object[]) ?? attribs.ToArray();
+ }
var attr = _type.GetTypeInfo().GetCustomAttributes(attributeType, inherit);
return (attr as object[]) ?? attr.ToArray();
diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs
index 75ca5dff37..818aa2e43b 100644
--- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Avalonia.Markup.Xaml.Context;
@@ -30,7 +29,7 @@ namespace Avalonia.Markup.Xaml.PortableXaml
type = base.GetXamlType(xamlNamespace, name, typeArguments);
}
}
- catch(Exception e)
+ catch (Exception e)
{
//TODO: log or wrap exception
throw e;
@@ -66,5 +65,15 @@ namespace Avalonia.Markup.Xaml.PortableXaml
protected override ICustomAttributeProvider GetCustomAttributeProvider(MemberInfo member)
=> new AvaloniaMemberAttributeProvider(member);
+
+ public override XamlType GetXamlType(Type type)
+ {
+ if (type.FullName.StartsWith("Avalonia."))
+ {
+ return new AvaloniaXamlType(type, this);
+ }
+
+ return base.GetXamlType(type);
+ }
}
}
\ 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
new file mode 100644
index 0000000000..ee1acbefa7
--- /dev/null
+++ b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs
@@ -0,0 +1,94 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using Portable.Xaml;
+using Portable.Xaml.Schema;
+using am = Avalonia.Metadata;
+
+namespace Avalonia.Markup.Xaml.PortableXaml
+{
+ public class AvaloniaXamlType : XamlType
+ {
+ public AvaloniaXamlType(Type underlyingType, XamlSchemaContext schemaContext) :
+ base(underlyingType, schemaContext)
+ {
+ }
+
+ protected override XamlMember LookupMember(string name, bool skipReadOnlyCheck)
+ {
+ var pi = UnderlyingType.GetRuntimeProperty(name);
+
+ var dependAttr = pi.GetCustomAttribute();
+
+ if (dependAttr != null)
+ {
+ return new DependOnXamlMember(dependAttr.Name, pi, SchemaContext);
+ }
+
+ return base.LookupMember(name, skipReadOnlyCheck);
+ }
+ }
+
+ public class DependOnXamlMember : XamlMember
+ {
+ private string _dependOn;
+
+ public DependOnXamlMember(string dependOn,
+ PropertyInfo propertyInfo,
+ XamlSchemaContext schemaContext) :
+ base(propertyInfo, schemaContext)
+ {
+ _dependOn = dependOn;
+ }
+
+ private XamlMember _dependOnMember;
+
+ public XamlMember DependOnMember
+ {
+ get
+ {
+ return _dependOnMember ??
+ (_dependOnMember = DeclaringType.GetMember(_dependOn));
+ }
+ }
+
+ protected override IList LookupDependsOn()
+ {
+ return new List() { DeclaringType.GetMember(_dependOn) };
+ }
+
+ protected override XamlMemberInvoker LookupInvoker()
+ {
+ return new DependOnInvoker(this);
+ }
+
+ private class DependOnInvoker : XamlMemberInvoker
+ {
+ public DependOnInvoker(XamlMember member) : base(member)
+ {
+ }
+
+ public override void SetValue(object instance, object value)
+ {
+ if (value is string &&
+ (Member.UnderlyingMember as PropertyInfo).PropertyType != typeof(string))
+ {
+ var dpm = (Member as DependOnXamlMember).DependOnMember.UnderlyingMember;
+ var pi = (dpm as PropertyInfo);
+ var avp = pi.GetValue(instance) as AvaloniaProperty;
+
+ Type targetType = avp != null ? avp.PropertyType : pi.PropertyType;
+
+ var xamTargetType = Member.DeclaringType.SchemaContext.GetXamlType(targetType);
+ var ttConv = xamTargetType?.TypeConverter?.ConverterInstance;
+ if (ttConv != null)
+ {
+ value = ttConv.ConvertFromString(value as string);
+ }
+ }
+
+ base.SetValue(instance, value);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/TypeDescriptorExtensions.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/TypeDescriptorExtensions.cs
new file mode 100644
index 0000000000..169befeb84
--- /dev/null
+++ b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/TypeDescriptorExtensions.cs
@@ -0,0 +1,37 @@
+using System;
+using Portable.Xaml.Markup;
+
+namespace Portable.Xaml.ComponentModel
+{
+ internal static class TypeDescriptorExtensions
+ {
+ ///
+ /// Gets the service from ITypeDescriptorContext
+ /// usually in TypeConverter in xaml reader context
+ /// examples:
+ /// context.GetService()
+ /// context.GetService()
+ /// context.GetService()
+ /// context.GetService()
+ /// context.GetService()
+ /// context.GetService()
+ /// context.GetService()
+ ///
+ /// Service Type
+ /// The TypeDescriptor context.
+ ///
+ public static T GetService(this ITypeDescriptorContext ctx) where T : class
+ {
+ return ctx.GetService(typeof(T)) as T;
+ }
+
+ public static Type ResolveType(this ITypeDescriptorContext ctx, string namespacePrefix, string type)
+ {
+ var tr = ctx.GetService();
+
+ string name = string.IsNullOrEmpty(namespacePrefix) ? type : $"{namespacePrefix}:{type}";
+
+ return tr?.Resolve(name);
+ }
+ }
+}
\ No newline at end of file