committed by
GitHub
52 changed files with 232 additions and 2424 deletions
@ -1,107 +0,0 @@ |
|||
using System; |
|||
using System.ComponentModel; |
|||
using System.Collections.Generic; |
|||
using System.Globalization; |
|||
using Avalonia.Collections; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml.Converters; |
|||
using Avalonia.Media.Imaging; |
|||
using Avalonia.Styling; |
|||
using Avalonia.Controls.Templates; |
|||
|
|||
namespace Avalonia.Markup.Xaml |
|||
{ |
|||
using System.Reflection; |
|||
using Avalonia.Media; |
|||
|
|||
/// <summary>
|
|||
/// Maintains a repository of <see cref="TypeConverter"/>s for XAML parsing on top of those
|
|||
/// maintained by <see cref="TypeDescriptor"/>.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// The default method of defining type converters using <see cref="TypeConverterAttribute"/>
|
|||
/// isn't powerful enough for our purposes:
|
|||
///
|
|||
/// - It doesn't handle non-constructed generic types (such as <see cref="AvaloniaList{T}"/>)
|
|||
/// - Type converters which require XAML features cannot be defined in non-XAML assemblies and
|
|||
/// so can't be referenced using <see cref="TypeConverterAttribute"/>
|
|||
/// - Many types have a static `Parse(string)` method which can be used implicitly; this class
|
|||
/// detects such methods and auto-creates a type converter
|
|||
/// </remarks>
|
|||
public static class AvaloniaTypeConverters |
|||
{ |
|||
// When adding item to that list make sure to modify AvaloniaXamlIlLanguage
|
|||
private static Dictionary<Type, Type> _converters = new Dictionary<Type, Type>() |
|||
{ |
|||
{ typeof(AvaloniaList<>), typeof(AvaloniaListConverter<>) }, |
|||
{ typeof(AvaloniaProperty), typeof(AvaloniaPropertyTypeConverter) }, |
|||
{ typeof(IBitmap), typeof(BitmapTypeConverter) }, |
|||
{ typeof(IList<Point>), typeof(PointsListTypeConverter) }, |
|||
{ typeof(IMemberSelector), typeof(MemberSelectorTypeConverter) }, |
|||
{ typeof(Selector), typeof(SelectorTypeConverter) }, |
|||
{ typeof(TimeSpan), typeof(TimeSpanTypeConverter) }, |
|||
{ typeof(WindowIcon), typeof(IconTypeConverter) }, |
|||
{ typeof(CultureInfo), typeof(CultureInfoConverter) }, |
|||
{ typeof(Uri), typeof(AvaloniaUriTypeConverter) }, |
|||
{ typeof(FontFamily), typeof(FontFamilyTypeConverter) }, |
|||
{ typeof(EventInfo), typeof(AvaloniaEventConverter) }, |
|||
}; |
|||
|
|||
internal static Type GetBuiltinTypeConverter(Type type) |
|||
{ |
|||
_converters.TryGetValue(type, out var result); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Tries to lookup a <see cref="TypeConverter"/> for a type.
|
|||
/// </summary>
|
|||
/// <param name="type">The type.</param>
|
|||
/// <returns>The type converter.</returns>
|
|||
public static Type GetTypeConverter(Type type) |
|||
{ |
|||
if (type.IsConstructedGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) |
|||
{ |
|||
var inner = GetTypeConverter(type.GetGenericArguments()[0]); |
|||
if (inner == null) |
|||
return null; |
|||
return typeof(NullableTypeConverter<>).MakeGenericType(inner); |
|||
} |
|||
|
|||
if (_converters.TryGetValue(type, out var result)) |
|||
{ |
|||
return result; |
|||
} |
|||
|
|||
// Converters for non-constructed generic types can't be specified using
|
|||
// TypeConverterAttribute. Allow them to be registered here and handle them sanely.
|
|||
if (type.IsConstructedGenericType && |
|||
_converters.TryGetValue(type.GetGenericTypeDefinition(), out result)) |
|||
{ |
|||
return result?.MakeGenericType(type.GetGenericArguments()); |
|||
} |
|||
|
|||
// If the type isn't a primitive or a type that XAML already handles, but has a static
|
|||
// Parse method, use that
|
|||
if (!type.IsPrimitive && |
|||
type != typeof(DateTime) && |
|||
type != typeof(Uri) && |
|||
ParseTypeConverter.HasParseMethod(type)) |
|||
{ |
|||
result = typeof(ParseTypeConverter<>).MakeGenericType(type); |
|||
_converters.Add(type, result); |
|||
return result; |
|||
} |
|||
|
|||
_converters.Add(type, null); |
|||
return null; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Registers a type converter for a type.
|
|||
/// </summary>
|
|||
/// <param name="type">The type. Maybe be a non-constructed generic type.</param>
|
|||
/// <param name="converterType">The converter type. Maybe be a non-constructed generic type.</param>
|
|||
public static void Register(Type type, Type converterType) => _converters[type] = converterType; |
|||
} |
|||
} |
|||
@ -1,99 +0,0 @@ |
|||
using System; |
|||
using System.ComponentModel; |
|||
using System.Globalization; |
|||
using System.Linq; |
|||
using System.Linq.Expressions; |
|||
using System.Reflection; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml.PortableXaml; |
|||
using Portable.Xaml; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Converters |
|||
{ |
|||
internal class AvaloniaEventConverter : TypeConverter |
|||
{ |
|||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) |
|||
{ |
|||
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); |
|||
} |
|||
|
|||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) |
|||
{ |
|||
var text = value as string; |
|||
if (text != null) |
|||
{ |
|||
var rootObjectProvider = context.GetService(typeof(IRootObjectProvider)) as IRootObjectProvider; |
|||
var destinationTypeProvider = context.GetService(typeof(IDestinationTypeProvider)) as IDestinationTypeProvider; |
|||
if (rootObjectProvider != null && destinationTypeProvider != null) |
|||
{ |
|||
var target = rootObjectProvider.RootObject; |
|||
var eventType = destinationTypeProvider.GetDestinationType(); |
|||
var eventParameters = eventType.GetRuntimeMethods().First(r => r.Name == "Invoke").GetParameters(); |
|||
// go in reverse to match System.Xaml behaviour
|
|||
var methods = target.GetType().GetRuntimeMethods().Reverse(); |
|||
|
|||
// find based on exact match parameter types first
|
|||
foreach (var method in methods) |
|||
{ |
|||
if (method.Name != text) |
|||
continue; |
|||
var parameters = method.GetParameters(); |
|||
if (eventParameters.Length != parameters.Length) |
|||
continue; |
|||
if (parameters.Length == 0) |
|||
return method.CreateDelegate(eventType, target); |
|||
|
|||
for (int i = 0; i < parameters.Length; i++) |
|||
{ |
|||
var param = parameters[i]; |
|||
var eventParam = eventParameters[i]; |
|||
if (param.ParameterType != eventParam.ParameterType) |
|||
break; |
|||
if (i == parameters.Length - 1) |
|||
return method.CreateDelegate(eventType, target); |
|||
} |
|||
} |
|||
|
|||
// EnhancedXaml: Find method with compatible base class parameters
|
|||
foreach (var method in methods) |
|||
{ |
|||
if (method.Name != text) |
|||
continue; |
|||
var parameters = method.GetParameters(); |
|||
if (parameters.Length == 0 || eventParameters.Length != parameters.Length) |
|||
continue; |
|||
|
|||
for (int i = 0; i < parameters.Length; i++) |
|||
{ |
|||
var param = parameters[i]; |
|||
var eventParam = eventParameters[i]; |
|||
if (!param.ParameterType.GetTypeInfo().IsAssignableFrom(eventParam.ParameterType.GetTypeInfo())) |
|||
break; |
|||
if (i == parameters.Length - 1) |
|||
return method.CreateDelegate(eventType, target); |
|||
} |
|||
} |
|||
|
|||
var contextProvider = (IXamlSchemaContextProvider)context.GetService(typeof(IXamlSchemaContextProvider)); |
|||
var avaloniaContext = (AvaloniaXamlSchemaContext)contextProvider.SchemaContext; |
|||
|
|||
if (avaloniaContext.IsDesignMode) |
|||
{ |
|||
// We want to ignore missing events in the designer, so if event handler
|
|||
// wasn't found create an empty delegate.
|
|||
var lambdaExpression = Expression.Lambda( |
|||
eventType, |
|||
Expression.Empty(), |
|||
eventParameters.Select(x => Expression.Parameter(x.ParameterType))); |
|||
return lambdaExpression.Compile(); |
|||
} |
|||
else |
|||
{ |
|||
throw new XamlObjectWriterException($"Referenced value method {text} in type {target.GetType()} indicated by event {eventType.FullName} was not found"); |
|||
} |
|||
} |
|||
} |
|||
return base.ConvertFrom(context, culture, value); |
|||
} |
|||
} |
|||
} |
|||
@ -1,89 +0,0 @@ |
|||
using System; |
|||
using System.Collections; |
|||
using System.ComponentModel; |
|||
using System.Globalization; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Converters |
|||
{ |
|||
public class NullableTypeConverter<T> : TypeConverter where T : TypeConverter, new() |
|||
{ |
|||
private TypeConverter _inner; |
|||
|
|||
public NullableTypeConverter() |
|||
{ |
|||
_inner = new T(); |
|||
} |
|||
|
|||
public NullableTypeConverter(TypeConverter inner) |
|||
{ |
|||
_inner = inner; |
|||
} |
|||
|
|||
|
|||
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) |
|||
{ |
|||
if (value == null) |
|||
return null; |
|||
return _inner.ConvertTo(context, culture, value, destinationType); |
|||
} |
|||
|
|||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) |
|||
{ |
|||
if (value == null) |
|||
return null; |
|||
if (value as string == "") |
|||
return null; |
|||
return _inner.ConvertFrom(context, culture, value); |
|||
} |
|||
|
|||
public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues) |
|||
{ |
|||
return _inner.CreateInstance(context, propertyValues); |
|||
} |
|||
|
|||
public override bool GetStandardValuesSupported(ITypeDescriptorContext context) |
|||
{ |
|||
return _inner.GetStandardValuesSupported(context); |
|||
} |
|||
|
|||
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) |
|||
{ |
|||
return _inner.GetStandardValuesExclusive(context); |
|||
} |
|||
|
|||
public override bool GetCreateInstanceSupported(ITypeDescriptorContext context) |
|||
{ |
|||
return _inner.GetCreateInstanceSupported(context); |
|||
} |
|||
|
|||
public override bool GetPropertiesSupported(ITypeDescriptorContext context) |
|||
{ |
|||
return _inner.GetPropertiesSupported(context); |
|||
} |
|||
|
|||
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) |
|||
{ |
|||
return _inner.GetStandardValues(context); |
|||
} |
|||
|
|||
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) |
|||
{ |
|||
return _inner.GetProperties(context, value, attributes); |
|||
} |
|||
|
|||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) |
|||
{ |
|||
return _inner.CanConvertTo(context, destinationType); |
|||
} |
|||
|
|||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) |
|||
{ |
|||
return _inner.CanConvertFrom(context, sourceType); |
|||
} |
|||
|
|||
public override bool IsValid(ITypeDescriptorContext context, object value) |
|||
{ |
|||
return _inner.IsValid(context, value); |
|||
} |
|||
} |
|||
} |
|||
@ -1,79 +0,0 @@ |
|||
using System; |
|||
using System.ComponentModel; |
|||
using System.Globalization; |
|||
using System.Reflection; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Converters |
|||
{ |
|||
/// <summary>
|
|||
/// Base class for type converters which call a static Parse method.
|
|||
/// </summary>
|
|||
public abstract class ParseTypeConverter : TypeConverter |
|||
{ |
|||
protected const BindingFlags PublicStatic = BindingFlags.Public | BindingFlags.Static; |
|||
protected static readonly Type[] StringParameter = new[] { typeof(string) }; |
|||
protected static readonly Type[] StringIFormatProviderParameters = new[] { typeof(string), typeof(IFormatProvider) }; |
|||
|
|||
/// <summary>
|
|||
/// Checks whether a type has a suitable Parse method.
|
|||
/// </summary>
|
|||
/// <param name="type">The type.</param>
|
|||
/// <returns>True if the type has a suitable parse method, otherwise false.</returns>
|
|||
public static bool HasParseMethod(Type type) |
|||
{ |
|||
return type.GetMethod("Parse", PublicStatic, null, StringIFormatProviderParameters, null) != null || |
|||
type.GetMethod("Parse", PublicStatic, null, StringParameter, null) != null; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// A type converter which calls a static Parse method.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type with the Parse method.</typeparam>
|
|||
public class ParseTypeConverter<T> : ParseTypeConverter |
|||
{ |
|||
private static Func<string, T> _parse; |
|||
private static Func<string, IFormatProvider, T> _parseWithFormat; |
|||
|
|||
static ParseTypeConverter() |
|||
{ |
|||
var method = typeof(T).GetMethod("Parse", PublicStatic, null, StringIFormatProviderParameters, null); |
|||
|
|||
if (method != null) |
|||
{ |
|||
_parseWithFormat = (Func<string, IFormatProvider, T>)method |
|||
.CreateDelegate(typeof(Func<string, IFormatProvider, T>)); |
|||
return; |
|||
} |
|||
|
|||
method = typeof(T).GetMethod("Parse", PublicStatic, null, StringParameter, null); |
|||
|
|||
if (method != null) |
|||
{ |
|||
_parse = (Func<string, T>)method.CreateDelegate(typeof(Func<string, T>)); |
|||
} |
|||
} |
|||
|
|||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) |
|||
{ |
|||
return sourceType == typeof(string); |
|||
} |
|||
|
|||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) |
|||
{ |
|||
if (value != null) |
|||
{ |
|||
if (_parse != null) |
|||
{ |
|||
return _parse(value.ToString()); |
|||
} |
|||
else if (_parseWithFormat != null) |
|||
{ |
|||
return _parseWithFormat(value.ToString(), culture); |
|||
} |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
// 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.Globalization; |
|||
using Avalonia.Markup.Parsers; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Converters |
|||
{ |
|||
using Portable.Xaml.ComponentModel; |
|||
using System.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(context.ResolveType); |
|||
|
|||
return parser.Parse((string)value); |
|||
} |
|||
} |
|||
} |
|||
@ -1,49 +0,0 @@ |
|||
// 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 Avalonia.Styling; |
|||
using Portable.Xaml; |
|||
using Portable.Xaml.ComponentModel; |
|||
using System.ComponentModel; |
|||
using Portable.Xaml.Markup; |
|||
using System; |
|||
using System.Globalization; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Converters |
|||
{ |
|||
public class SetterValueTypeConverter : TypeConverter |
|||
{ |
|||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) |
|||
{ |
|||
return sourceType == typeof(string); |
|||
} |
|||
|
|||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) |
|||
{ |
|||
object setter = context.GetService<IProvideValueTarget>().TargetObject; |
|||
var schemaContext = context.GetService<IXamlSchemaContextProvider>().SchemaContext; |
|||
|
|||
return ConvertSetterValue(context, schemaContext, culture, (setter as Setter), value); |
|||
} |
|||
|
|||
[Obsolete("TODO: try assosiate Setter.Value property with SetterValueTypeConverter, so far coouldn't make it :(")] |
|||
internal static object ConvertSetterValue(ITypeDescriptorContext dcontext, XamlSchemaContext context, CultureInfo info, Setter setter, object value) |
|||
{ |
|||
Type targetType = setter?.Property?.PropertyType; |
|||
|
|||
if (targetType == null) |
|||
{ |
|||
return value; |
|||
} |
|||
|
|||
var ttConv = context.GetXamlType(targetType)?.TypeConverter?.ConverterInstance; |
|||
|
|||
if (ttConv != null) |
|||
{ |
|||
value = ttConv.ConvertFromString(dcontext, info, value as string); |
|||
} |
|||
|
|||
return value; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using System; |
|||
|
|||
namespace Avalonia.Markup.Xaml |
|||
{ |
|||
public abstract class MarkupExtension |
|||
{ |
|||
public abstract object ProvideValue(IServiceProvider serviceProvider); |
|||
} |
|||
} |
|||
@ -1,39 +0,0 @@ |
|||
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(); |
|||
} |
|||
|
|||
public static pm.DependsOnAttribute ToPortableXaml(this avm.DependsOnAttribute attrib) |
|||
{ |
|||
if (attrib == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
return new pm.DependsOnAttribute(attrib.Name); |
|||
} |
|||
} |
|||
} |
|||
@ -1,83 +0,0 @@ |
|||
using Avalonia.Markup.Xaml.Converters; |
|||
using Avalonia.Styling; |
|||
using Portable.Xaml.ComponentModel; |
|||
using System.ComponentModel; |
|||
using System; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using avm = Avalonia.Metadata; |
|||
using pm = Portable.Xaml.Markup; |
|||
|
|||
namespace Avalonia.Markup.Xaml.PortableXaml |
|||
{ |
|||
public class AvaloniaMemberAttributeProvider : ICustomAttributeProvider |
|||
{ |
|||
public AvaloniaMemberAttributeProvider(MemberInfo info) |
|||
{ |
|||
_info = info; |
|||
} |
|||
|
|||
public object[] GetCustomAttributes(bool inherit) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
public object[] GetCustomAttributes(Type attributeType, bool inherit) |
|||
{ |
|||
Attribute result = null; |
|||
|
|||
if (attributeType == typeof(pm.XamlDeferLoadAttribute)) |
|||
{ |
|||
result = _info.GetCustomAttribute<avm.TemplateContentAttribute>(inherit) |
|||
.ToPortableXaml(); |
|||
} |
|||
else if (attributeType == typeof(pm.AmbientAttribute)) |
|||
{ |
|||
result = _info.GetCustomAttribute<avm.AmbientAttribute>(inherit) |
|||
.ToPortableXaml(); |
|||
} |
|||
else if (attributeType == typeof(pm.DependsOnAttribute)) |
|||
{ |
|||
result = _info.GetCustomAttribute<avm.DependsOnAttribute>(inherit) |
|||
.ToPortableXaml(); |
|||
} |
|||
else if (attributeType == typeof(TypeConverterAttribute) && |
|||
_info.DeclaringType == typeof(Setter) && |
|||
_info.Name == nameof(Setter.Value)) |
|||
{ |
|||
//actually it never comes here looks like if property type is object
|
|||
//Portable.Xaml is not searching for Type Converter
|
|||
result = new TypeConverterAttribute(typeof(SetterValueTypeConverter)); |
|||
} |
|||
else if (attributeType == typeof(TypeConverterAttribute) && _info is EventInfo) |
|||
{ |
|||
// If a type converter for `EventInfo` is registered, then use that to convert
|
|||
// event handler values. This is used by the designer to override the lookup
|
|||
// for event handlers with a null handler.
|
|||
var eventConverter = AvaloniaTypeConverters.GetTypeConverter(typeof(EventInfo)); |
|||
|
|||
if (eventConverter != null) |
|||
{ |
|||
result = new TypeConverterAttribute(eventConverter); |
|||
} |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
var attr = _info.GetCustomAttributes(attributeType, inherit); |
|||
return (attr as object[]) ?? attr.ToArray(); |
|||
} |
|||
else |
|||
{ |
|||
return new object[] { result }; |
|||
} |
|||
} |
|||
|
|||
public bool IsDefined(Type attributeType, bool inherit) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
private readonly MemberInfo _info; |
|||
} |
|||
} |
|||
@ -1,56 +0,0 @@ |
|||
using System.Collections.Generic; |
|||
using Avalonia.Controls; |
|||
|
|||
namespace Avalonia.Markup.Xaml.PortableXaml |
|||
{ |
|||
internal class AvaloniaNameScope : Portable.Xaml.Markup.INameScope |
|||
{ |
|||
public object Instance { get; set; } |
|||
|
|||
private Dictionary<string, object> _names = new Dictionary<string, object>(); |
|||
|
|||
public object FindName(string name) |
|||
{ |
|||
object result; |
|||
if (_names.TryGetValue(name, out result)) |
|||
return result; |
|||
return null; |
|||
} |
|||
|
|||
public void RegisterName(string name, object scopedElement) |
|||
{ |
|||
if (scopedElement != null) |
|||
_names.Add(name, scopedElement); |
|||
|
|||
//TODO: ???
|
|||
//var control = scopedElement as Control;
|
|||
|
|||
//if (control != null)
|
|||
//{
|
|||
// var nameScope = (Instance as INameScope) ?? control.FindNameScope();
|
|||
|
|||
// if (nameScope != null)
|
|||
// {
|
|||
// nameScope.Register(name, scopedElement);
|
|||
// }
|
|||
//}
|
|||
} |
|||
|
|||
public void UnregisterName(string name) |
|||
{ |
|||
} |
|||
|
|||
public void RegisterOnNameScope(object target) |
|||
{ |
|||
var nameScope = target as INameScope; |
|||
|
|||
if (nameScope != null) |
|||
{ |
|||
foreach (var v in _names) |
|||
{ |
|||
nameScope.Register(v.Key, v.Value); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,147 +0,0 @@ |
|||
// 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.Linq; |
|||
using System.Reflection; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Data; |
|||
using Avalonia.Markup.Xaml.Templates; |
|||
using Avalonia.Media; |
|||
using Avalonia.Metadata; |
|||
using Avalonia.Platform; |
|||
using Avalonia.Styling; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Context |
|||
{ |
|||
using ClrNamespaceInfo = Tuple<string, Assembly>; |
|||
|
|||
public interface IRuntimeTypeProvider |
|||
{ |
|||
Type FindType(string xamlNamespace, string name, Type[] genArgs); |
|||
|
|||
IEnumerable<Assembly> ReferencedAssemblies { get; } |
|||
} |
|||
|
|||
public class AvaloniaRuntimeTypeProvider : IRuntimeTypeProvider |
|||
{ |
|||
private const string ClrNamespace = "clr-namespace:"; |
|||
// private const string AvaloniaNs = "https://github.com/avaloniaui";
|
|||
|
|||
private static readonly IEnumerable<Assembly> ForcedAssemblies = new[] |
|||
{ |
|||
typeof(AvaloniaObject).GetTypeInfo().Assembly, |
|||
typeof(Animation.Animation).GetTypeInfo().Assembly, |
|||
typeof(Control).GetTypeInfo().Assembly, |
|||
typeof(Style).GetTypeInfo().Assembly, |
|||
typeof(DataTemplate).GetTypeInfo().Assembly, |
|||
typeof(SolidColorBrush).GetTypeInfo().Assembly, |
|||
typeof(Binding).GetTypeInfo().Assembly, |
|||
}; |
|||
|
|||
private Dictionary<string, HashSet<ClrNamespaceInfo>> _namespaces = new Dictionary<string, HashSet<ClrNamespaceInfo>>(); |
|||
|
|||
private List<Assembly> _scanned = new List<Assembly>(); |
|||
|
|||
public IEnumerable<Assembly> ReferencedAssemblies => _scanned; |
|||
|
|||
public AvaloniaRuntimeTypeProvider() |
|||
{ |
|||
ScanAssemblies(ForcedAssemblies); |
|||
ScanNewAssemblies(); |
|||
} |
|||
|
|||
private static bool IsClrNamespace(string ns) |
|||
{ |
|||
return ns.StartsWith(ClrNamespace); |
|||
} |
|||
|
|||
private static Assembly GetAssembly(string assemblyName) |
|||
{ |
|||
return Assembly.Load(new AssemblyName(assemblyName)); |
|||
} |
|||
|
|||
private void ScanAssemblies(IEnumerable<Assembly> assemblies) |
|||
{ |
|||
foreach (var assembly in assemblies) |
|||
{ |
|||
var namespaces = assembly.GetCustomAttributes<XmlnsDefinitionAttribute>() |
|||
.Select(x => new { x.XmlNamespace, x.ClrNamespace }) |
|||
.GroupBy(x => x.XmlNamespace); |
|||
|
|||
foreach (var nsa in namespaces) |
|||
{ |
|||
HashSet<ClrNamespaceInfo> reg; |
|||
|
|||
if (!_namespaces.TryGetValue(nsa.Key, out reg)) |
|||
{ |
|||
_namespaces[nsa.Key] = reg = new HashSet<Tuple<string, Assembly>>(); |
|||
} |
|||
|
|||
foreach (var child in nsa) |
|||
{ |
|||
reg.Add(new ClrNamespaceInfo(child.ClrNamespace, assembly)); |
|||
} |
|||
} |
|||
|
|||
_scanned.Add(assembly); |
|||
} |
|||
} |
|||
|
|||
private void ScanNewAssemblies() |
|||
{ |
|||
IEnumerable<Assembly> assemblies = AppDomain.CurrentDomain.GetAssemblies(); |
|||
|
|||
if (assemblies != null) |
|||
{ |
|||
assemblies = assemblies.Except(_scanned); |
|||
ScanAssemblies(assemblies); |
|||
} |
|||
} |
|||
|
|||
private Dictionary<string, Type> _typeCache = new Dictionary<string, Type>(); |
|||
|
|||
public Type FindType(string xamlNamespace, string name, Type[] genArgs) |
|||
{ |
|||
if (IsClrNamespace(xamlNamespace)) |
|||
{ |
|||
//we need to handle only xaml url namespaces for avalonia,
|
|||
//the other namespaces are handled well in portable.xaml
|
|||
return null; |
|||
} |
|||
|
|||
string key = $"{xamlNamespace}:{name}"; |
|||
|
|||
Type type; |
|||
|
|||
if (_typeCache.TryGetValue(key, out type)) |
|||
{ |
|||
return type; |
|||
} |
|||
|
|||
HashSet<ClrNamespaceInfo> reg; |
|||
|
|||
if (!_namespaces.TryGetValue(xamlNamespace, out reg)) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
if (genArgs != null) |
|||
name += "`" + genArgs.Length; |
|||
|
|||
foreach (var ns in reg) |
|||
{ |
|||
var n = ns.Item1 + "." + name; |
|||
var t = ns.Item2.GetType(n); |
|||
if (t != null) |
|||
{ |
|||
_typeCache[key] = t; |
|||
return t; |
|||
} |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
} |
|||
@ -1,117 +0,0 @@ |
|||
// 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.ComponentModel; |
|||
using System; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using avm = Avalonia.Metadata; |
|||
using pm = Portable.Xaml.Markup; |
|||
|
|||
namespace Avalonia.Markup.Xaml.PortableXaml |
|||
{ |
|||
internal class AvaloniaTypeAttributeProvider : ICustomAttributeProvider |
|||
{ |
|||
public AvaloniaTypeAttributeProvider(Type type) |
|||
{ |
|||
_type = type; |
|||
} |
|||
|
|||
public object[] GetCustomAttributes(bool inherit) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
public object[] GetCustomAttributes(Type attributeType, bool inherit) |
|||
{ |
|||
Attribute result = null; |
|||
|
|||
var ti = _type.GetTypeInfo(); |
|||
|
|||
if (attributeType == typeof(pm.ContentPropertyAttribute)) |
|||
{ |
|||
result = GetContentPropertyAttribute(inherit); |
|||
} |
|||
else if (attributeType == typeof(pm.RuntimeNamePropertyAttribute)) |
|||
{ |
|||
if (_namedType.IsAssignableFrom(ti)) |
|||
{ |
|||
result = new pm.RuntimeNamePropertyAttribute(nameof(INamed.Name)); |
|||
} |
|||
} |
|||
else if (attributeType == typeof(TypeConverterAttribute)) |
|||
{ |
|||
var builtin = AvaloniaTypeConverters.GetBuiltinTypeConverter(_type); |
|||
if (builtin != null) |
|||
result = new TypeConverterAttribute(builtin); |
|||
result = result ?? ti.GetCustomAttribute(attributeType, inherit); |
|||
|
|||
if (result == null) |
|||
{ |
|||
var convType = AvaloniaTypeConverters.GetTypeConverter(_type); |
|||
|
|||
if (convType != null) |
|||
{ |
|||
result = new TypeConverterAttribute(convType); |
|||
} |
|||
} |
|||
} |
|||
else if (attributeType == typeof(pm.AmbientAttribute)) |
|||
{ |
|||
result = ti.GetCustomAttribute<avm.AmbientAttribute>(inherit) |
|||
.ToPortableXaml(); |
|||
} |
|||
|
|||
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) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
private readonly TypeInfo _namedType = typeof(INamed).GetTypeInfo(); |
|||
|
|||
private readonly Type _type; |
|||
|
|||
private Attribute GetContentPropertyAttribute(bool inherit) |
|||
{ |
|||
var type = _type; |
|||
|
|||
while (type != null) |
|||
{ |
|||
var properties = type.GetTypeInfo().DeclaredProperties |
|||
.Where(x => x.GetCustomAttribute<avm.ContentAttribute>() != null); |
|||
string result = null; |
|||
|
|||
foreach (var property in properties) |
|||
{ |
|||
if (result != null) |
|||
{ |
|||
throw new Exception($"Content property defined more than once on {type}."); |
|||
} |
|||
|
|||
result = property.Name; |
|||
} |
|||
|
|||
if (result != null) |
|||
{ |
|||
return new pm.ContentPropertyAttribute(result); |
|||
} |
|||
|
|||
type = inherit ? type.GetTypeInfo().BaseType : null; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
} |
|||
@ -1,31 +0,0 @@ |
|||
using Portable.Xaml; |
|||
using Portable.Xaml.Markup; |
|||
using System; |
|||
using System.Reflection; |
|||
|
|||
namespace Avalonia.Markup.Xaml.PortableXaml |
|||
{ |
|||
public class AvaloniaXamlContext : IUriContext |
|||
{ |
|||
private AvaloniaXamlContext() |
|||
{ |
|||
} |
|||
|
|||
public Assembly LocalAssembly { get; private set; } |
|||
|
|||
public Uri BaseUri { get; set; } |
|||
|
|||
public object RootInstance { get; private set; } |
|||
|
|||
internal static AvaloniaXamlContext For(XamlXmlReaderSettings sett, |
|||
object rootInstance) |
|||
{ |
|||
return new AvaloniaXamlContext() |
|||
{ |
|||
BaseUri = sett.BaseUri, |
|||
LocalAssembly = sett.LocalAssembly, |
|||
RootInstance = rootInstance |
|||
}; |
|||
} |
|||
} |
|||
} |
|||
@ -1,222 +0,0 @@ |
|||
using Avalonia.Data; |
|||
using Portable.Xaml; |
|||
using Portable.Xaml.ComponentModel; |
|||
using System.ComponentModel; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using Avalonia.Controls; |
|||
using Portable.Xaml.Schema; |
|||
|
|||
namespace Avalonia.Markup.Xaml.PortableXaml |
|||
{ |
|||
class AvaloniaXamlObjectWriter : XamlObjectWriter |
|||
{ |
|||
private static Dictionary<XamlDirective, string> DesignDirectives = new Dictionary<string, string> |
|||
{ |
|||
["DataContext"] = "DataContext", |
|||
["DesignWidth"] = "Width", ["DesignHeight"] = "Height", ["PreviewWith"] = "PreviewWith" |
|||
} |
|||
.ToDictionary(p => new XamlDirective( |
|||
new[] {"http://schemas.microsoft.com/expression/blend/2008"}, p.Key, |
|||
XamlLanguage.Object, null, AllowedMemberLocations.Attribute), p => p.Value); |
|||
|
|||
private readonly AvaloniaXamlSchemaContext _schemaContext; |
|||
|
|||
public static AvaloniaXamlObjectWriter Create( |
|||
AvaloniaXamlSchemaContext schemaContext, |
|||
AvaloniaXamlContext context, |
|||
IAmbientProvider parentAmbientProvider = null) |
|||
{ |
|||
var nameScope = new AvaloniaNameScope { Instance = context?.RootInstance }; |
|||
|
|||
var writerSettings = new XamlObjectWriterSettings() |
|||
{ |
|||
ExternalNameScope = nameScope, |
|||
RegisterNamesOnExternalNamescope = true, |
|||
RootObjectInstance = context?.RootInstance |
|||
}; |
|||
|
|||
return new AvaloniaXamlObjectWriter(schemaContext, |
|||
writerSettings.WithContext(context), |
|||
nameScope, |
|||
parentAmbientProvider); |
|||
} |
|||
|
|||
private readonly DelayedValuesHelper _delayedValuesHelper = new DelayedValuesHelper(); |
|||
|
|||
private AvaloniaNameScope _nameScope; |
|||
|
|||
private AvaloniaXamlObjectWriter( |
|||
AvaloniaXamlSchemaContext schemaContext, |
|||
XamlObjectWriterSettings settings, |
|||
AvaloniaNameScope nameScope, |
|||
IAmbientProvider parentAmbientProvider) |
|||
: base(schemaContext, settings, parentAmbientProvider) |
|||
{ |
|||
_nameScope = nameScope; |
|||
_schemaContext = schemaContext; |
|||
} |
|||
|
|||
protected override void Dispose(bool disposing) |
|||
{ |
|||
if (disposing) |
|||
{ |
|||
if (_nameScope != null && Result != null) |
|||
{ |
|||
_nameScope.RegisterOnNameScope(Result); |
|||
} |
|||
} |
|||
|
|||
base.Dispose(disposing); |
|||
} |
|||
|
|||
public void ApplyAllDelayedProperties() |
|||
{ |
|||
//HACK: We need this because Begin/EndInit ordering is broken
|
|||
_delayedValuesHelper.ApplyAll(); |
|||
} |
|||
|
|||
protected internal override void OnAfterProperties(object value) |
|||
{ |
|||
_delayedValuesHelper.EndInit(value); |
|||
|
|||
base.OnAfterProperties(value); |
|||
} |
|||
|
|||
protected internal override void OnBeforeProperties(object value) |
|||
{ |
|||
if (value != null) |
|||
_delayedValuesHelper.BeginInit(value); |
|||
|
|||
base.OnBeforeProperties(value); |
|||
} |
|||
|
|||
protected internal override bool OnSetValue(object target, XamlMember member, object value) |
|||
{ |
|||
if (_delayedValuesHelper.TryAdd(target, member, value)) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
return base.OnSetValue(target, member, value); |
|||
} |
|||
|
|||
public override void WriteStartMember(XamlMember property) |
|||
{ |
|||
foreach(var d in DesignDirectives) |
|||
if (property == d.Key && _schemaContext.IsDesignMode) |
|||
{ |
|||
base.WriteStartMember(new XamlMember(d.Value, |
|||
typeof(Design).GetMethod("Get" + d.Value, BindingFlags.Static | BindingFlags.Public), |
|||
typeof(Design).GetMethod("Set" + d.Value, BindingFlags.Static | BindingFlags.Public), |
|||
SchemaContext)); |
|||
return; |
|||
} |
|||
base.WriteStartMember(property); |
|||
} |
|||
|
|||
private class DelayedValuesHelper |
|||
{ |
|||
private int _cnt; |
|||
|
|||
private HashSet<object> _targets = new HashSet<object>(); |
|||
|
|||
private IList<DelayedValue> _values = new List<DelayedValue>(); |
|||
|
|||
private IEnumerable<DelayedValue> Values => _values; |
|||
|
|||
public void BeginInit(object target) |
|||
{ |
|||
++_cnt; |
|||
|
|||
AddTargetIfNeeded(target); |
|||
} |
|||
|
|||
public void EndInit(object target) |
|||
{ |
|||
--_cnt; |
|||
|
|||
if (_cnt == 0) |
|||
{ |
|||
ApplyAll(); |
|||
} |
|||
} |
|||
|
|||
public bool TryAdd(object target, XamlMember member, object value) |
|||
{ |
|||
if (value is IBinding) |
|||
{ |
|||
Add(new DelayedValue(target, member, value)); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
private 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 AddTargetIfNeeded(object target) |
|||
{ |
|||
if (!_targets.Contains(target)) |
|||
{ |
|||
Add(new DelayedValue(target, null, null)); |
|||
} |
|||
} |
|||
|
|||
public void ApplyAll() |
|||
{ |
|||
//TODO: revisit this
|
|||
//apply delayed values and clear
|
|||
//that's the last object let's set all delayed bindings
|
|||
foreach (var dv in Values.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) |
|||
{ |
|||
var target = v.Target; |
|||
|
|||
if (_targets.Contains(target)) |
|||
{ |
|||
_targets.Remove(target); |
|||
(target as ISupportInitialize)?.EndInit(); |
|||
} |
|||
} |
|||
|
|||
_targets.Clear(); |
|||
_values.Clear(); |
|||
} |
|||
|
|||
private class DelayedValue |
|||
{ |
|||
public DelayedValue(object target, XamlMember member, object value) |
|||
{ |
|||
Target = target; |
|||
Member = member; |
|||
Value = value; |
|||
} |
|||
|
|||
public XamlMember Member { get; } |
|||
public object Target { get; } |
|||
public object Value { get; } |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,327 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using Avalonia.Data; |
|||
using Avalonia.Markup.Xaml.Context; |
|||
using Avalonia.Markup.Xaml.MarkupExtensions; |
|||
using Avalonia.Markup.Xaml.Styling; |
|||
using Portable.Xaml; |
|||
|
|||
namespace Avalonia.Markup.Xaml.PortableXaml |
|||
{ |
|||
internal class AvaloniaXamlSchemaContext : XamlSchemaContext |
|||
{ |
|||
private static AvaloniaXamlSchemaContext s_instance; |
|||
private static AvaloniaXamlSchemaContext s_designInstance; |
|||
|
|||
public static AvaloniaXamlSchemaContext Instance |
|||
{ |
|||
get |
|||
{ |
|||
if (s_instance == null) |
|||
{ |
|||
s_instance = Create(); |
|||
} |
|||
|
|||
return s_instance; |
|||
} |
|||
} |
|||
|
|||
public static AvaloniaXamlSchemaContext DesignInstance |
|||
{ |
|||
get |
|||
{ |
|||
if (s_designInstance == null) |
|||
{ |
|||
s_designInstance = Create(); |
|||
s_designInstance.IsDesignMode = true; |
|||
} |
|||
|
|||
return s_designInstance; |
|||
} |
|||
} |
|||
|
|||
public bool IsDesignMode { get; private set; } |
|||
public static AvaloniaXamlSchemaContext Create(IRuntimeTypeProvider typeProvider = null) |
|||
{ |
|||
return new AvaloniaXamlSchemaContext(typeProvider ?? new AvaloniaRuntimeTypeProvider()); |
|||
} |
|||
|
|||
private AvaloniaXamlSchemaContext(IRuntimeTypeProvider typeProvider) |
|||
//better not set the references assemblies
|
|||
//TODO: check this on iOS
|
|||
//: base(typeProvider.ReferencedAssemblies)
|
|||
{ |
|||
Contract.Requires<ArgumentNullException>(typeProvider != null); |
|||
|
|||
_avaloniaTypeProvider = typeProvider; |
|||
} |
|||
|
|||
private IRuntimeTypeProvider _avaloniaTypeProvider; |
|||
|
|||
protected override XamlType GetXamlType(string xamlNamespace, string name, params XamlType[] typeArguments) |
|||
{ |
|||
XamlType type = null; |
|||
try |
|||
{ |
|||
type = ResolveXamlTypeName(xamlNamespace, name, typeArguments, false); |
|||
|
|||
if (type == null) |
|||
{ |
|||
type = base.GetXamlType(xamlNamespace, name, typeArguments); |
|||
} |
|||
} |
|||
catch (Exception e) |
|||
{ |
|||
//TODO: log or wrap exception
|
|||
throw e; |
|||
} |
|||
return type; |
|||
} |
|||
|
|||
private XamlType ResolveXamlTypeName(string xmlNamespace, string xmlLocalName, XamlType[] typeArguments, bool required) |
|||
{ |
|||
Type[] genArgs = null; |
|||
if (typeArguments != null && typeArguments.Any()) |
|||
{ |
|||
genArgs = typeArguments.Select(t => t?.UnderlyingType).ToArray(); |
|||
|
|||
if (genArgs.Any(t => t == null)) |
|||
{ |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
// 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) |
|||
{ |
|||
Type extType; |
|||
if (_wellKnownExtensionTypes.TryGetValue(type, out extType)) |
|||
{ |
|||
type = extType; |
|||
} |
|||
} |
|||
|
|||
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
|
|||
return ResolveSimpleTypeName(xmlNamespace, xmlLocalName); |
|||
} |
|||
|
|||
return GetXamlType(type); |
|||
} |
|||
|
|||
#region Workaround for bug in Portablexaml system types like double,int etc ...
|
|||
|
|||
private static Type[] _simpleTypes = new Type[] |
|||
{ |
|||
typeof(bool), |
|||
typeof(byte), |
|||
typeof(char), |
|||
typeof(decimal), |
|||
typeof(double), |
|||
typeof(Int16), |
|||
typeof(Int32), |
|||
typeof(Int64), |
|||
typeof(float), |
|||
typeof(string), |
|||
typeof(TimeSpan), |
|||
typeof(Uri), |
|||
}; |
|||
|
|||
private static Dictionary<Tuple<string, string>, XamlType> _simpleXamlTypes; |
|||
|
|||
//in Portable xaml like xmlns:sys='clr-namespace:System;assembly=mscorlib'
|
|||
//and sys:Double is not resolved properly
|
|||
[Obsolete("TODO: remove once it's fixed in Portable.xaml")] |
|||
private static XamlType ResolveSimpleTypeName(string xmlNamespace, string xmlLocalName) |
|||
{ |
|||
if (_simpleXamlTypes == null) |
|||
{ |
|||
_simpleXamlTypes = new Dictionary<Tuple<string, string>, XamlType>(); |
|||
|
|||
foreach (var type in _simpleTypes) |
|||
{ |
|||
string asmName = type.GetTypeInfo().Assembly.GetName().Name; |
|||
string ns = $"clr-namespace:{type.Namespace};assembly={asmName}"; |
|||
var xamlType = XamlLanguage.AllTypes.First(t => t.UnderlyingType == type); |
|||
_simpleXamlTypes.Add(new Tuple<string, string>(ns, type.Name), xamlType); |
|||
} |
|||
} |
|||
|
|||
XamlType result; |
|||
|
|||
var key = new Tuple<string, string>(xmlNamespace, xmlLocalName); |
|||
|
|||
_simpleXamlTypes.TryGetValue(key, out result); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
#endregion Workaround for bug in Portablexaml system types like double,int etc ...
|
|||
|
|||
protected internal override ICustomAttributeProvider GetCustomAttributeProvider(Type type) |
|||
=> new AvaloniaTypeAttributeProvider(type); |
|||
|
|||
protected internal override ICustomAttributeProvider GetCustomAttributeProvider(MemberInfo member) |
|||
=> new AvaloniaMemberAttributeProvider(member); |
|||
|
|||
public override XamlType GetXamlType(Type type) |
|||
{ |
|||
XamlType result = null; |
|||
|
|||
if (_cachedTypes.TryGetValue(type, out result)) |
|||
{ |
|||
return result; |
|||
} |
|||
|
|||
_cachedTypes[type] = result = GetAvaloniaXamlType(type) ?? base.GetXamlType(type); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
private static readonly Dictionary<Type, Type> _wellKnownExtensionTypes = new Dictionary<Type, Type>() |
|||
{ |
|||
{ typeof(Binding), typeof(BindingExtension) }, |
|||
{ typeof(StyleInclude), typeof(StyleIncludeExtension) }, |
|||
}; |
|||
|
|||
private XamlType GetAvaloniaXamlType(Type type) |
|||
{ |
|||
//if type is extension get the original type to check
|
|||
var origType = _wellKnownExtensionTypes.FirstOrDefault(v => v.Value == type).Key; |
|||
|
|||
if (typeof(IBinding).GetTypeInfo().IsAssignableFrom((origType ?? type).GetTypeInfo())) |
|||
{ |
|||
return new BindingXamlType(type, this); |
|||
} |
|||
|
|||
if (origType != null || |
|||
typeof(AvaloniaObject).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo())) |
|||
{ |
|||
return new AvaloniaXamlType(type, this); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
protected internal override XamlMember GetAttachableProperty(string attachablePropertyName, MethodInfo getter, MethodInfo setter) |
|||
{ |
|||
var key = MemberKey.Create(getter ?? setter, attachablePropertyName, "a"); |
|||
|
|||
XamlMember result; |
|||
|
|||
if (_cachedMembers.TryGetValue(key, out result)) |
|||
{ |
|||
return result; |
|||
} |
|||
|
|||
var type = (getter ?? setter).DeclaringType; |
|||
|
|||
var prop = AvaloniaPropertyRegistry.Instance.FindRegistered(type, 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 internal override XamlMember GetProperty(PropertyInfo pi) |
|||
{ |
|||
Type objType = pi.DeclaringType; |
|||
string name = pi.Name; |
|||
|
|||
XamlMember result; |
|||
|
|||
var key = MemberKey.Create(pi, "p"); |
|||
|
|||
if (_cachedMembers.TryGetValue(key, out result)) |
|||
{ |
|||
return result; |
|||
} |
|||
|
|||
var avProp = AvaloniaPropertyRegistry.Instance.FindRegistered(objType, name); |
|||
|
|||
if (avProp != null) |
|||
{ |
|||
result = new AvaloniaPropertyXamlMember(avProp, pi, this); |
|||
} |
|||
|
|||
if (result == null) |
|||
{ |
|||
result = new PropertyXamlMember(pi, this); |
|||
} |
|||
|
|||
return _cachedMembers[key] = result; |
|||
} |
|||
|
|||
private Dictionary<Type, XamlType> _cachedTypes = new Dictionary<Type, XamlType>(); |
|||
|
|||
private Dictionary<MemberKey, XamlMember> _cachedMembers = new Dictionary<MemberKey, XamlMember>(); |
|||
|
|||
private struct MemberKey |
|||
{ |
|||
public static MemberKey Create(MemberInfo m, string name, string memberType) |
|||
{ |
|||
return new MemberKey(m.DeclaringType, name, memberType); |
|||
} |
|||
|
|||
public static MemberKey Create(MemberInfo m, string memberType) |
|||
{ |
|||
return Create(m, m.Name, memberType); |
|||
} |
|||
|
|||
public MemberKey(Type type, object member, string memberType) |
|||
{ |
|||
Type = type; |
|||
Member = member; |
|||
MemberType = memberType; |
|||
} |
|||
|
|||
public Type Type { get; } |
|||
|
|||
public object Member { get; } |
|||
|
|||
public string MemberType { get; } |
|||
|
|||
public override string ToString() |
|||
{ |
|||
return $"{MemberType}:{Type.Namespace}:{Type.Name}.{Member}"; |
|||
} |
|||
} |
|||
|
|||
|
|||
public override bool TryGetCompatibleXamlNamespace(string xamlNamespace, out string compatibleNamespace) |
|||
{ |
|||
//Forces XamlXmlReader to not ignore our namespace in design mode if mc:Ignorable is set
|
|||
if (IsDesignMode && |
|||
xamlNamespace == "http://schemas.microsoft.com/expression/blend/2008") |
|||
{ |
|||
compatibleNamespace = xamlNamespace; |
|||
return true; |
|||
} |
|||
|
|||
return base.TryGetCompatibleXamlNamespace(xamlNamespace, out compatibleNamespace); |
|||
} |
|||
|
|||
} |
|||
} |
|||
@ -1,388 +0,0 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Data; |
|||
using Avalonia.Markup.Data; |
|||
using Avalonia.Metadata; |
|||
using Avalonia.Styling; |
|||
using Portable.Xaml; |
|||
using Portable.Xaml.Schema; |
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Globalization; |
|||
using System.Reflection; |
|||
using System.Xml.Serialization; |
|||
|
|||
namespace Avalonia.Markup.Xaml.PortableXaml |
|||
{ |
|||
using Converters; |
|||
using PropertyKey = Tuple<Type, string>; |
|||
|
|||
public class AvaloniaXamlType : XamlType |
|||
{ |
|||
static readonly AvaloniaPropertyTypeConverter propertyTypeConverter = new AvaloniaPropertyTypeConverter(); |
|||
|
|||
public AvaloniaXamlType(Type underlyingType, XamlSchemaContext schemaContext) : |
|||
base(underlyingType, schemaContext) |
|||
{ |
|||
} |
|||
|
|||
protected override XamlMember LookupAttachableMember(string name) |
|||
{ |
|||
var m = base.LookupAttachableMember(name); |
|||
|
|||
if (m == null) |
|||
{ |
|||
// Might be an AddOwnered attached property.
|
|||
var avProp = AvaloniaPropertyRegistry.Instance.FindRegistered(UnderlyingType, name); |
|||
|
|||
if (avProp?.IsAttached == true) |
|||
{ |
|||
return new AvaloniaPropertyXamlMember(avProp, this); |
|||
} |
|||
} |
|||
|
|||
return m; |
|||
} |
|||
|
|||
protected override XamlMember LookupMember(string name, bool skipReadOnlyCheck) |
|||
{ |
|||
var m = base.LookupMember(name, skipReadOnlyCheck); |
|||
|
|||
if (m == null && !name.Contains(".")) |
|||
{ |
|||
//so far Portable.xaml haven't found the member/property
|
|||
//but what if we have AvaloniaProperty
|
|||
//without setter and/or without getter
|
|||
//let's try to find the AvaloniaProperty as a fallback
|
|||
var avProp = AvaloniaPropertyRegistry.Instance.FindRegistered(UnderlyingType, name); |
|||
|
|||
if (avProp != null && !(skipReadOnlyCheck && avProp.IsReadOnly)) |
|||
{ |
|||
m = new AvaloniaPropertyXamlMember(avProp, this); |
|||
} |
|||
} |
|||
|
|||
return m; |
|||
} |
|||
} |
|||
|
|||
public class BindingXamlType : XamlType |
|||
{ |
|||
private static List<Type> _notAssignable = |
|||
new List<Type> |
|||
{ |
|||
typeof (IXmlSerializable) |
|||
}; |
|||
|
|||
public BindingXamlType(Type underlyingType, XamlSchemaContext schemaContext) : |
|||
base(underlyingType, schemaContext) |
|||
{ |
|||
} |
|||
|
|||
public override bool CanAssignTo(XamlType xamlType) |
|||
{ |
|||
return !_notAssignable.Contains(xamlType.UnderlyingType); |
|||
} |
|||
} |
|||
|
|||
public class PropertyXamlMember : XamlMember |
|||
{ |
|||
public PropertyXamlMember(PropertyInfo propertyInfo, XamlSchemaContext schemaContext) |
|||
: base(propertyInfo, schemaContext) |
|||
{ |
|||
} |
|||
|
|||
protected PropertyXamlMember(string attachablePropertyName, |
|||
MethodInfo getter, MethodInfo setter, XamlSchemaContext schemaContext) |
|||
: base(attachablePropertyName, getter, setter, schemaContext) |
|||
{ |
|||
} |
|||
|
|||
protected PropertyXamlMember(string name, XamlType declaringType, bool isAttachable) |
|||
: base(name, declaringType, isAttachable) |
|||
{ |
|||
} |
|||
|
|||
private bool IsReadOnlyCollectionProperty |
|||
{ |
|||
get |
|||
{ |
|||
//Collection properties like:
|
|||
//MultiBinding.Bindings, Panel.Children, Control.Styles,
|
|||
//need to be readonly for Portable.Xaml
|
|||
//Collection properties like:
|
|||
//Grid.RowDefinitions, Grid.ColumnDefinitions
|
|||
//need to be set only once, and subsequent changes to be
|
|||
//added to collection
|
|||
//TODO: investigate is this good enough as solution ???
|
|||
//We can add some ReadOnyXamlPropertyCollectionAttribute to cover this
|
|||
return Type.IsCollection; |
|||
} |
|||
} |
|||
|
|||
private bool HasCollectionTypeConverter |
|||
{ |
|||
get |
|||
{ |
|||
return Type.IsCollection && Type.TypeConverter != null; |
|||
} |
|||
} |
|||
|
|||
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
|
|||
|
|||
if (IsReadOnlyCollectionProperty && |
|||
!HasCollectionTypeConverter) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
return base.LookupUnderlyingSetter(); |
|||
} |
|||
|
|||
protected override XamlMemberInvoker LookupInvoker() |
|||
{ |
|||
//if we have a IList property and it has TypeConverter
|
|||
//Portable.xaml need to be able to set the value
|
|||
//but instead directly set new value we'll sync the lists
|
|||
bool updateListInsteadSet = HasCollectionTypeConverter; |
|||
return new PropertyInvoker(this) |
|||
{ |
|||
UpdateListInsteadSet = updateListInsteadSet |
|||
}; |
|||
} |
|||
|
|||
protected override bool LookupIsUnknown() => false; |
|||
|
|||
protected override XamlType LookupType() |
|||
{ |
|||
var propType = GetPropertyType(); |
|||
|
|||
if (propType != null) |
|||
{ |
|||
if (propType == typeof(IEnumerable)) |
|||
{ |
|||
//TODO: Portable.xaml is not handling well IEnumerable
|
|||
//let's threat IEnumerable property as list
|
|||
//revisit this when smarter solution is found
|
|||
propType = typeof(IList); |
|||
} |
|||
|
|||
return DeclaringType.SchemaContext.GetXamlType(propType); |
|||
} |
|||
|
|||
return base.LookupType(); |
|||
} |
|||
|
|||
protected virtual Type GetPropertyType() |
|||
{ |
|||
return (UnderlyingMember as PropertyInfo)?.PropertyType; |
|||
} |
|||
|
|||
private IList<XamlMember> _dependsOn; |
|||
|
|||
protected override IList<XamlMember> LookupDependsOn() |
|||
{ |
|||
if (_dependsOn == null) |
|||
{ |
|||
var attrib = UnderlyingMember.GetCustomAttribute<DependsOnAttribute>(true); |
|||
|
|||
if (attrib != null) |
|||
{ |
|||
var member = DeclaringType.GetMember(attrib.Name); |
|||
|
|||
_dependsOn = new XamlMember[] { member }; |
|||
} |
|||
else |
|||
{ |
|||
_dependsOn = base.LookupDependsOn(); |
|||
} |
|||
} |
|||
|
|||
return _dependsOn; |
|||
} |
|||
|
|||
private PropertyKey PropertyKey() |
|||
=> new PropertyKey(DeclaringType.UnderlyingType, Name); |
|||
|
|||
private class PropertyInvoker : XamlMemberInvoker |
|||
{ |
|||
public bool UpdateListInsteadSet { get; set; } = false; |
|||
|
|||
public PropertyInvoker(XamlMember member) : base(member) |
|||
{ |
|||
} |
|||
|
|||
public override void SetValue(object instance, object value) |
|||
{ |
|||
//can't make it work to assign TypeConverter to Setter.Value
|
|||
//so we need it hard coded
|
|||
//TODO: try to assosiate TypeConverter with Setter.Value
|
|||
//and remove this lines
|
|||
if (instance is Setter && |
|||
Member.Name == nameof(Setter.Value) && |
|||
value is string) |
|||
{ |
|||
value = SetterValueTypeConverter.ConvertSetterValue(null, |
|||
Member.DeclaringType.SchemaContext, CultureInfo.InvariantCulture, |
|||
instance as Setter, |
|||
value); |
|||
} |
|||
|
|||
if (UpdateListInsteadSet && |
|||
value != null && |
|||
UpdateListInsteadSetValue(instance, value)) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
base.SetValue(instance, value); |
|||
} |
|||
|
|||
private bool UpdateListInsteadSetValue(object instance, object value) |
|||
{ |
|||
object old = GetValue(instance); |
|||
|
|||
if (Equals(old, value)) |
|||
{ |
|||
//don't set the same collection value
|
|||
return true; |
|||
} |
|||
else if (old is IList && value is IList) |
|||
{ |
|||
var oldList = (IList)old; |
|||
var curList = (IList)value; |
|||
|
|||
oldList.Clear(); |
|||
|
|||
foreach (object item in curList) |
|||
{ |
|||
oldList.Add(item); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class AvaloniaPropertyXamlMember : PropertyXamlMember |
|||
{ |
|||
private bool? _assignBinding; |
|||
|
|||
public bool AssignBinding => (bool)(_assignBinding ?? (_assignBinding = UnderlyingMember?.GetCustomAttribute<AssignBindingAttribute>() != null)); |
|||
|
|||
public AvaloniaProperty Property { get; } |
|||
|
|||
public AvaloniaPropertyXamlMember(AvaloniaProperty property, |
|||
PropertyInfo propertyInfo, |
|||
XamlSchemaContext schemaContext) : |
|||
base(propertyInfo, schemaContext) |
|||
{ |
|||
Property = property; |
|||
} |
|||
|
|||
public AvaloniaPropertyXamlMember(AvaloniaProperty property, XamlType type) : |
|||
base(property.Name, type, false) |
|||
{ |
|||
Property = property; |
|||
} |
|||
|
|||
protected AvaloniaPropertyXamlMember(AvaloniaProperty property, |
|||
string attachablePropertyName, |
|||
MethodInfo getter, MethodInfo setter, XamlSchemaContext schemaContext) |
|||
: base(attachablePropertyName, getter, setter, schemaContext) |
|||
{ |
|||
Property = property; |
|||
} |
|||
|
|||
protected override XamlMemberInvoker LookupInvoker() |
|||
{ |
|||
return new AvaloniaPropertyInvoker(this); |
|||
} |
|||
|
|||
protected override bool LookupIsReadOnly() |
|||
{ |
|||
return Property.IsReadOnly; |
|||
} |
|||
|
|||
protected override Type GetPropertyType() |
|||
{ |
|||
return Property.PropertyType; |
|||
} |
|||
|
|||
private class AvaloniaPropertyInvoker : XamlMemberInvoker |
|||
{ |
|||
public AvaloniaPropertyInvoker(XamlMember member) : base(member) |
|||
{ |
|||
} |
|||
|
|||
public override void SetValue(object instance, object value) |
|||
{ |
|||
if (Property != null) |
|||
{ |
|||
var obj = ((IAvaloniaObject)instance); |
|||
if (value is IBinding) |
|||
{ |
|||
if (!Member.AssignBinding) |
|||
ApplyBinding(obj, (IBinding)value); |
|||
else |
|||
obj.SetValue(Property, value); |
|||
} |
|||
else |
|||
{ |
|||
obj.SetValue(Property, value); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
base.SetValue(instance, value); |
|||
} |
|||
} |
|||
|
|||
public override object GetValue(object instance) |
|||
{ |
|||
if (Property != null && !Property.IsAttached) |
|||
{ |
|||
return ((IAvaloniaObject)instance).GetValue(Property); |
|||
} |
|||
else |
|||
{ |
|||
return base.GetValue(instance); |
|||
} |
|||
} |
|||
|
|||
private void ApplyBinding(IAvaloniaObject obj, IBinding binding) |
|||
{ |
|||
var control = obj as IControl; |
|||
var property = Property; |
|||
|
|||
if (control != null && property != Control.DataContextProperty) |
|||
DelayedBinding.Add(control, property, binding); |
|||
else |
|||
obj.Bind(property, binding); |
|||
} |
|||
|
|||
private AvaloniaProperty Property => Member.Property; |
|||
|
|||
private new AvaloniaPropertyXamlMember Member => |
|||
(AvaloniaPropertyXamlMember)base.Member; |
|||
} |
|||
} |
|||
|
|||
public class AvaloniaAttachedPropertyXamlMember : AvaloniaPropertyXamlMember |
|||
{ |
|||
public AvaloniaAttachedPropertyXamlMember(AvaloniaProperty property, |
|||
string attachablePropertyName, |
|||
MethodInfo getter, MethodInfo setter, |
|||
XamlSchemaContext schemaContext) |
|||
: base(property, attachablePropertyName, getter, setter, schemaContext) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,101 +0,0 @@ |
|||
using Avalonia.Markup.Xaml.PortableXaml; |
|||
using Portable.Xaml.Markup; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using System.ComponentModel; |
|||
|
|||
namespace Portable.Xaml.ComponentModel |
|||
{ |
|||
internal static class TypeDescriptorExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the service from ITypeDescriptorContext
|
|||
/// usually in TypeConverter in xaml reader context
|
|||
/// examples:
|
|||
/// context.GetService<IXamlTypeResolver>()
|
|||
/// context.GetService<IXamlNamespaceResolver>()
|
|||
/// context.GetService<IXamlNameProvider>()
|
|||
/// context.GetService<INamespacePrefixLookup>()
|
|||
/// context.GetService<IXamlSchemaContextProvider>()
|
|||
/// context.GetService<IRootObjectProvider>()
|
|||
/// context.GetService<IProvideValueTarget>()
|
|||
/// </summary>
|
|||
/// <typeparam name="T">Service Type</typeparam>
|
|||
/// <param name="ctx">The TypeDescriptor context.</param>
|
|||
/// <returns></returns>
|
|||
public static T GetService<T>(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<IXamlTypeResolver>(); |
|||
|
|||
string name = string.IsNullOrEmpty(namespacePrefix) ? type : $"{namespacePrefix}:{type}"; |
|||
|
|||
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; |
|||
|
|||
// Because GetFirstParent uses XamlType.CanAssignTo it returns values that
|
|||
// aren't actually of the correct type. Use GetAllAmbientValues instead.
|
|||
return amb.GetAllAmbientValues(sc.GetXamlType(typeof(T))).OfType<T>().FirstOrDefault(); |
|||
} |
|||
|
|||
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>(); |
|||
} |
|||
|
|||
public static Uri GetBaseUri(this ITypeDescriptorContext ctx) |
|||
{ |
|||
return ctx.GetWriterSettings()?.Context?.BaseUri; |
|||
} |
|||
|
|||
public static Assembly GetLocalAssembly(this ITypeDescriptorContext ctx) |
|||
{ |
|||
return ctx.GetWriterSettings()?.Context?.LocalAssembly; |
|||
} |
|||
|
|||
public static AvaloniaXamlContext GetAvaloniaXamlContext(this ITypeDescriptorContext ctx) |
|||
{ |
|||
return ctx.GetWriterSettings()?.Context; |
|||
} |
|||
|
|||
public static XamlObjectWriterSettings WithContext(this XamlObjectWriterSettings settings, AvaloniaXamlContext context) |
|||
{ |
|||
return new AvaloniaXamlObjectWriterSettings(settings, context); |
|||
} |
|||
|
|||
private static AvaloniaXamlObjectWriterSettings GetWriterSettings(this ITypeDescriptorContext ctx) |
|||
{ |
|||
return ctx.GetService<IXamlObjectWriterFactory>().GetParentSettings() as AvaloniaXamlObjectWriterSettings; |
|||
} |
|||
|
|||
private class AvaloniaXamlObjectWriterSettings : XamlObjectWriterSettings |
|||
{ |
|||
public AvaloniaXamlObjectWriterSettings(XamlObjectWriterSettings settings, AvaloniaXamlContext context) |
|||
: base(settings) |
|||
{ |
|||
Context = context; |
|||
} |
|||
|
|||
public AvaloniaXamlContext Context { get; } |
|||
} |
|||
} |
|||
} |
|||
@ -1 +0,0 @@ |
|||
Subproject commit ab5526173722b8988bc5ca3c03c8752ce89c0975 |
|||
@ -1,26 +0,0 @@ |
|||
// 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.
|
|||
|
|||
namespace Avalonia.Markup.Xaml.Templates |
|||
{ |
|||
using Portable.Xaml; |
|||
using Portable.Xaml.ComponentModel; |
|||
using System.ComponentModel; |
|||
using System; |
|||
|
|||
public class TemplateLoader : XamlDeferringLoader |
|||
{ |
|||
public override object Load(XamlReader xamlReader, IServiceProvider serviceProvider) |
|||
{ |
|||
var tdc = (ITypeDescriptorContext)serviceProvider; |
|||
var ns = tdc.GetService<IXamlNamespaceResolver>(); |
|||
var ambientProvider = tdc.GetService<IAmbientProvider>(); |
|||
return new TemplateContent(ns.GetNamespacePrefixes(), xamlReader, ambientProvider); |
|||
} |
|||
|
|||
public override XamlReader Save(object value, IServiceProvider serviceProvider) |
|||
{ |
|||
return ((TemplateContent)value).List.GetReader(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
using System; |
|||
|
|||
namespace Avalonia.Markup.Xaml |
|||
{ |
|||
public interface IProvideValueTarget |
|||
{ |
|||
object TargetObject { get; } |
|||
object TargetProperty { get; } |
|||
} |
|||
|
|||
public interface IRootObjectProvider |
|||
{ |
|||
object RootObject { get; } |
|||
} |
|||
|
|||
public interface IUriContext |
|||
{ |
|||
Uri BaseUri { get; set; } |
|||
} |
|||
|
|||
public interface IXamlTypeResolver |
|||
{ |
|||
Type Resolve (string qualifiedTypeName); |
|||
} |
|||
|
|||
|
|||
public class ConstructorArgumentAttribute : Attribute |
|||
{ |
|||
public ConstructorArgumentAttribute(string name) |
|||
{ |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -1,6 +1,8 @@ |
|||
<Application xmlns="https://github.com/avaloniaui"> |
|||
<Application xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
x:Class="Avalonia.DesignerSupport.TestApp.App"> |
|||
<Application.Styles> |
|||
<StyleInclude Source="resm:Avalonia.Themes.Default.DefaultTheme.xaml?assembly=Avalonia.Themes.Default"/> |
|||
<StyleInclude Source="resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default"/> |
|||
</Application.Styles> |
|||
</Application> |
|||
</Application> |
|||
|
|||
@ -1,5 +1,7 @@ |
|||
<Window xmlns="https://github.com/avaloniaui" |
|||
xmlns:pages="clr-namespace:ControlCatalog.Pages;assembly=ControlCatalog" |
|||
Title="TESTAPP"> |
|||
Title="TESTAPP" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
x:Class="Avalonia.DesignerSupport.TestApp.MainWindow"> |
|||
<Button/> |
|||
</Window> |
|||
</Window> |
|||
|
|||
Loading…
Reference in new issue