Browse Source

WIP almost working fine, style resource binding and minor improvements

pull/916/head
donandren 9 years ago
committed by Andrey Kunchev
parent
commit
5aa306d4e8
  1. 1
      src/Avalonia.Base/Avalonia.Base.csproj
  2. 15
      src/Avalonia.Base/Metadata/AmbientAttribute.cs
  3. 2
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  4. 28
      src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs
  5. 5
      src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs
  6. 4
      src/Markup/Avalonia.Markup.Xaml/Data/StyleResourceBinding.cs
  7. 12
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs
  8. 15
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs
  9. 14
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TypeExtension.cs
  10. 29
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AttributeExtensions.cs
  11. 38
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaMemberAttributeProvider.cs
  12. 51
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs
  13. 183
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs
  14. 77
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs
  15. 153
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs
  16. 23
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/TypeDescriptorExtensions.cs
  17. 68
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/XamlBinding.cs

1
src/Avalonia.Base/Avalonia.Base.csproj

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

15
src/Avalonia.Base/Metadata/AmbientAttribute.cs

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

2
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

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

28
src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoaderPortableXaml.cs

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

5
src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs

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

4
src/Markup/Avalonia.Markup.Xaml/Data/StyleResourceBinding.cs

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

12
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs

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

15
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs

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

14
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TypeExtension.cs

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

29
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AttributeExtensions.cs

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

38
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaMemberAttributeProvider.cs

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

51
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaTypeAttributeProvider.cs

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

183
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlObjectWriter.cs

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

77
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlSchemaContext.cs

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

153
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs

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

23
src/Markup/Avalonia.Markup.Xaml/PortableXaml/TypeDescriptorExtensions.cs

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

68
src/Markup/Avalonia.Markup.Xaml/PortableXaml/XamlBinding.cs

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