diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs index 1de5cb06c6..3e70f549f3 100644 --- a/src/Avalonia.Base/AvaloniaProperty.cs +++ b/src/Avalonia.Base/AvaloniaProperty.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Reactive.Subjects; using System.Reflection; using Avalonia.Data; +using Avalonia.Data.Core; using Avalonia.Utilities; namespace Avalonia @@ -14,7 +15,7 @@ namespace Avalonia /// /// Base class for avalonia properties. /// - public class AvaloniaProperty : IEquatable + public class AvaloniaProperty : IEquatable, IPropertyInfo { /// /// Represents an unset property value. @@ -546,7 +547,10 @@ namespace Avalonia } } - + bool IPropertyInfo.CanGet => true; + bool IPropertyInfo.CanSet => true; + object IPropertyInfo.Get(object target) => ((AvaloniaObject)target).GetValue(this); + void IPropertyInfo.Set(object target, object value) => ((AvaloniaObject)target).SetValue(this, value); } /// /// Class representing the . diff --git a/src/Avalonia.Base/Data/Core/ClrPropertyInfo.cs b/src/Avalonia.Base/Data/Core/ClrPropertyInfo.cs new file mode 100644 index 0000000000..05059b6617 --- /dev/null +++ b/src/Avalonia.Base/Data/Core/ClrPropertyInfo.cs @@ -0,0 +1,70 @@ +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace Avalonia.Data.Core +{ + public class ClrPropertyInfo : IPropertyInfo + { + private readonly Func _getter; + private readonly Action _setter; + + public ClrPropertyInfo(string name, Func getter, Action setter) + { + _getter = getter; + _setter = setter; + Name = name; + } + + public string Name { get; } + public object Get(object target) + { + if (_getter == null) + throw new NotSupportedException("Property " + Name + " doesn't have a getter"); + return _getter(target); + } + + public void Set(object target, object value) + { + if (_setter == null) + throw new NotSupportedException("Property " + Name + " doesn't have a setter"); + _setter(target, value); + } + + public bool CanSet => _setter != null; + public bool CanGet => _getter != null; + } + + public class ReflectionClrPropertyInfo : ClrPropertyInfo + { + static Action CreateSetter(PropertyInfo info) + { + if (info.SetMethod == null) + return null; + var target = Expression.Parameter(typeof(object), "target"); + var value = Expression.Parameter(typeof(object), "value"); + return Expression.Lambda>( + Expression.Call(Expression.Convert(target, info.DeclaringType), info.SetMethod, + Expression.Convert(value, info.SetMethod.GetParameters()[0].ParameterType)), + target, value) + .Compile(); + } + + static Func CreateGetter(PropertyInfo info) + { + if (info.GetMethod == null) + return null; + var target = Expression.Parameter(typeof(object), "target"); + return Expression.Lambda>( + Expression.Convert(Expression.Call(Expression.Convert(target, info.DeclaringType), info.GetMethod), + typeof(object))) + .Compile(); + } + + public ReflectionClrPropertyInfo(PropertyInfo info) : base(info.Name, + CreateGetter(info), CreateSetter(info)) + { + + } + } +} diff --git a/src/Avalonia.Base/Data/Core/IPropertyInfo.cs b/src/Avalonia.Base/Data/Core/IPropertyInfo.cs new file mode 100644 index 0000000000..530b98d08b --- /dev/null +++ b/src/Avalonia.Base/Data/Core/IPropertyInfo.cs @@ -0,0 +1,11 @@ +namespace Avalonia.Data.Core +{ + public interface IPropertyInfo + { + string Name { get; } + object Get(object target); + void Set(object target, object value); + bool CanSet { get; } + bool CanGet { get; } + } +} diff --git a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs index c54d8e19a1..4981b27959 100644 --- a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs +++ b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs @@ -49,13 +49,18 @@ namespace Avalonia.Build.Tasks if (avares.Resources.Count(CheckXamlName) == 0 && emres.Resources.Count(CheckXamlName) == 0) // Nothing to do return new CompileResult(true); + + var clrPropertiesDef = new TypeDefinition("CompiledAvaloniaXaml", "XamlIlHelpers", + TypeAttributes.Class, asm.MainModule.TypeSystem.Object); + asm.MainModule.Types.Add(clrPropertiesDef); var xamlLanguage = AvaloniaXamlIlLanguage.Configure(typeSystem); - var compilerConfig = new XamlIlTransformerConfiguration(typeSystem, + var compilerConfig = new AvaloniaXamlIlCompilerConfiguration(typeSystem, typeSystem.TargetAssembly, xamlLanguage, XamlIlXmlnsMappings.Resolve(typeSystem, xamlLanguage), - AvaloniaXamlIlLanguage.CustomValueConverter); + AvaloniaXamlIlLanguage.CustomValueConverter, + new XamlIlClrPropertyInfoEmitter(typeSystem.CreateTypeBuilder(clrPropertiesDef))); var contextDef = new TypeDefinition("CompiledAvaloniaXaml", "XamlIlContext", diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj index 6f3dabd568..91d0feedfb 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj +++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj @@ -38,6 +38,7 @@ + @@ -55,6 +56,7 @@ + diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs index 167b75603f..5f95ae55a9 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs @@ -114,11 +114,15 @@ namespace Avalonia.Markup.Xaml.XamlIl InitializeSre(); var asm = localAssembly == null ? null : _sreTypeSystem.GetAssembly(localAssembly); + + var tb = _sreBuilder.DefineType("Builder_" + Guid.NewGuid().ToString("N") + "_" + uri); + var clrPropertyBuilder = tb.DefineNestedType("ClrProperties_" + Guid.NewGuid().ToString("N")); - var compiler = new AvaloniaXamlIlCompiler(new XamlIlTransformerConfiguration(_sreTypeSystem, asm, - _sreMappings, _sreXmlns, AvaloniaXamlIlLanguage.CustomValueConverter), + var compiler = new AvaloniaXamlIlCompiler(new AvaloniaXamlIlCompilerConfiguration(_sreTypeSystem, asm, + _sreMappings, _sreXmlns, AvaloniaXamlIlLanguage.CustomValueConverter, + new XamlIlClrPropertyInfoEmitter(_sreTypeSystem.CreateTypeBuilder(clrPropertyBuilder))), _sreContextType); - var tb = _sreBuilder.DefineType("Builder_" + Guid.NewGuid().ToString("N") + "_" + uri); + IXamlIlType overrideType = null; if (rootInstance != null) @@ -129,6 +133,7 @@ namespace Avalonia.Markup.Xaml.XamlIl compiler.IsDesignMode = isDesignMode; compiler.ParseAndCompile(xaml, uri?.ToString(), null, _sreTypeSystem.CreateTypeBuilder(tb), overrideType); var created = tb.CreateTypeInfo(); + clrPropertyBuilder.CreateTypeInfo(); return LoadOrPopulate(created, rootInstance); } diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompiler.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompiler.cs index b84f50fa8d..0d0b0e6967 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompiler.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompiler.cs @@ -16,7 +16,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions private readonly IXamlIlType _contextType; private readonly AvaloniaXamlIlDesignPropertiesTransformer _designTransformer; - private AvaloniaXamlIlCompiler(XamlIlTransformerConfiguration configuration) : base(configuration, true) + private AvaloniaXamlIlCompiler(AvaloniaXamlIlCompilerConfiguration configuration) : base(configuration, true) { _configuration = configuration; @@ -57,14 +57,14 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions } - public AvaloniaXamlIlCompiler(XamlIlTransformerConfiguration configuration, + public AvaloniaXamlIlCompiler(AvaloniaXamlIlCompilerConfiguration configuration, IXamlIlTypeBuilder contextTypeBuilder) : this(configuration) { _contextType = CreateContextType(contextTypeBuilder); } - public AvaloniaXamlIlCompiler(XamlIlTransformerConfiguration configuration, + public AvaloniaXamlIlCompiler(AvaloniaXamlIlCompilerConfiguration configuration, IXamlIlType contextType) : this(configuration) { _contextType = contextType; diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompilerConfiguration.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompilerConfiguration.cs new file mode 100644 index 0000000000..26965ffea4 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompilerConfiguration.cs @@ -0,0 +1,21 @@ +using XamlIl.Transform; +using XamlIl.TypeSystem; + +namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions +{ + class AvaloniaXamlIlCompilerConfiguration : XamlIlTransformerConfiguration + { + public XamlIlClrPropertyInfoEmitter ClrPropertyEmitter { get; } + + public AvaloniaXamlIlCompilerConfiguration(IXamlIlTypeSystem typeSystem, + IXamlIlAssembly defaultAssembly, + XamlIlLanguageTypeMappings typeMappings, + XamlIlXmlnsMappings xmlnsMappings, + XamlIlValueConverter customValueConverter, + XamlIlClrPropertyInfoEmitter clrPropertyEmitter) : base(typeSystem, defaultAssembly, typeMappings, xmlnsMappings, customValueConverter) + { + ClrPropertyEmitter = clrPropertyEmitter; + AddExtra(ClrPropertyEmitter); + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs index c25e1186d0..dad69da3be 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs @@ -50,7 +50,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions }, InnerServiceProviderFactoryMethod = runtimeHelpers.FindMethod(m => m.Name == "CreateInnerServiceProviderV1"), - ProvideValueTargetPropertyEmitter = XamlIlAvaloniaPropertyHelper.Emit, + ProvideValueTargetPropertyEmitter = XamlIlAvaloniaPropertyHelper.EmitProvideValueTarget, }; rv.CustomAttributeResolver = new AttributeResolver(typeSystem, rv); return rv; diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs index c054e57380..4c118899dc 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs @@ -19,26 +19,30 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers public IXamlIlType Transitions { get; } public IXamlIlType AssignBindingAttribute { get; } public IXamlIlType UnsetValueType { get; } + public IXamlIlType IPropertyInfo { get; } + public IXamlIlType ClrPropertyInfo { get; } - public AvaloniaXamlIlWellKnownTypes(XamlIlAstTransformationContext ctx) + public AvaloniaXamlIlWellKnownTypes(XamlIlTransformerConfiguration cfg) { - XamlIlTypes = ctx.Configuration.WellKnownTypes; - AvaloniaObject = ctx.Configuration.TypeSystem.GetType("Avalonia.AvaloniaObject"); - IAvaloniaObject = ctx.Configuration.TypeSystem.GetType("Avalonia.IAvaloniaObject"); - AvaloniaObjectExtensions = ctx.Configuration.TypeSystem.GetType("Avalonia.AvaloniaObjectExtensions"); - AvaloniaProperty = ctx.Configuration.TypeSystem.GetType("Avalonia.AvaloniaProperty"); - AvaloniaPropertyT = ctx.Configuration.TypeSystem.GetType("Avalonia.AvaloniaProperty`1"); - BindingPriority = ctx.Configuration.TypeSystem.GetType("Avalonia.Data.BindingPriority"); - IBinding = ctx.Configuration.TypeSystem.GetType("Avalonia.Data.IBinding"); - IDisposable = ctx.Configuration.TypeSystem.GetType("System.IDisposable"); - Transitions = ctx.Configuration.TypeSystem.GetType("Avalonia.Animation.Transitions"); - AssignBindingAttribute = ctx.Configuration.TypeSystem.GetType("Avalonia.Data.AssignBindingAttribute"); + XamlIlTypes = cfg.WellKnownTypes; + AvaloniaObject = cfg.TypeSystem.GetType("Avalonia.AvaloniaObject"); + IAvaloniaObject = cfg.TypeSystem.GetType("Avalonia.IAvaloniaObject"); + AvaloniaObjectExtensions = cfg.TypeSystem.GetType("Avalonia.AvaloniaObjectExtensions"); + AvaloniaProperty = cfg.TypeSystem.GetType("Avalonia.AvaloniaProperty"); + AvaloniaPropertyT = cfg.TypeSystem.GetType("Avalonia.AvaloniaProperty`1"); + BindingPriority = cfg.TypeSystem.GetType("Avalonia.Data.BindingPriority"); + IBinding = cfg.TypeSystem.GetType("Avalonia.Data.IBinding"); + IDisposable = cfg.TypeSystem.GetType("System.IDisposable"); + Transitions = cfg.TypeSystem.GetType("Avalonia.Animation.Transitions"); + AssignBindingAttribute = cfg.TypeSystem.GetType("Avalonia.Data.AssignBindingAttribute"); AvaloniaObjectBindMethod = AvaloniaObjectExtensions.FindMethod("Bind", IDisposable, false, IAvaloniaObject, AvaloniaProperty, - IBinding, ctx.Configuration.WellKnownTypes.Object); - UnsetValueType = ctx.Configuration.TypeSystem.GetType("Avalonia.UnsetValueType"); + IBinding, cfg.WellKnownTypes.Object); + UnsetValueType = cfg.TypeSystem.GetType("Avalonia.UnsetValueType"); AvaloniaObjectSetValueMethod = AvaloniaObject.FindMethod("SetValue", XamlIlTypes.Void, false, AvaloniaProperty, XamlIlTypes.Object, BindingPriority); + IPropertyInfo = cfg.TypeSystem.GetType("Avalonia.Data.Core.IPropertyInfo"); + ClrPropertyInfo = cfg.TypeSystem.GetType("Avalonia.Data.Core.ClrPropertyInfo"); } } @@ -48,7 +52,15 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { if (ctx.TryGetItem(out var rv)) return rv; - ctx.SetItem(rv = new AvaloniaXamlIlWellKnownTypes(ctx)); + ctx.SetItem(rv = new AvaloniaXamlIlWellKnownTypes(ctx.Configuration)); + return rv; + } + + public static AvaloniaXamlIlWellKnownTypes GetAvaloniaTypes(this XamlIlEmitContext ctx) + { + if (ctx.TryGetItem(out var rv)) + return rv; + ctx.SetItem(rv = new AvaloniaXamlIlWellKnownTypes(ctx.Configuration)); return rv; } } diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs index 6fc83cb5a5..e0783364db 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs @@ -15,6 +15,20 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions { class XamlIlAvaloniaPropertyHelper { + public static bool EmitProvideValueTarget(XamlIlEmitContext context, IXamlIlEmitter emitter, + XamlIlAstClrProperty property) + { + if (Emit(context, emitter, property)) + return true; + var foundClr = property.DeclaringType.Properties.FirstOrDefault(p => p.Name == property.Name); + if (foundClr == null) + return false; + context + .Configuration.GetExtra() + .Emit(context, emitter, foundClr); + return true; + } + public static bool Emit(XamlIlEmitContext context, IXamlIlEmitter emitter, XamlIlAstClrProperty property) { if (property is IXamlIlAvaloniaProperty ap) diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlClrPropertyInfoHelper.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlClrPropertyInfoHelper.cs new file mode 100644 index 0000000000..5b681e94a9 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlClrPropertyInfoHelper.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers; +using XamlIl.Ast; +using XamlIl.Transform; +using XamlIl.TypeSystem; + +namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions +{ + class XamlIlClrPropertyInfoHelper + { + + class ClrPropertyInfoNode : XamlIlAstNode, IXamlIlAstValueNode + { + public ClrPropertyInfoNode(AvaloniaXamlIlWellKnownTypes types, IXamlIlLineInfo lineInfo) : + base(lineInfo) + { + Type = new XamlIlAstClrTypeReference(this, types.XamlIlTypes.Object, false); + } + + public IXamlIlAstTypeReference Type { get; } + } + } + + class XamlIlClrPropertyInfoEmitter + { + private readonly IXamlIlTypeBuilder _builder; + + private Dictionary> _fields + = new Dictionary>(); + + public XamlIlClrPropertyInfoEmitter(IXamlIlTypeBuilder builder) + { + _builder = builder; + } + + static string GetKey(IXamlIlProperty property) + => property.Getter.DeclaringType.GetFullName() + "." + property.Name; + + public IXamlIlType Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen, IXamlIlProperty property) + { + var types = context.GetAvaloniaTypes(); + IXamlIlMethod Get() + { + var key = GetKey(property); + if (!_fields.TryGetValue(key, out var lst)) + _fields[key] = lst = new List<(IXamlIlProperty prop, IXamlIlMethod get)>(); + + foreach (var cached in lst) + { + if ( + ((cached.prop.Getter == null && property.Getter == null) || + cached.prop.Getter?.Equals(property.Getter) == true) && + ((cached.prop.Setter == null && property.Setter == null) || + cached.prop.Setter?.Equals(property.Setter) == true) + ) + return cached.get; + } + + var name = lst.Count == 0 ? key : key + "_" + Guid.NewGuid().ToString("N"); + + var field = _builder.DefineField(types.IPropertyInfo, name + "!Field", false, true); + + var getter = property.Getter == null ? + null : + _builder.DefineMethod(types.XamlIlTypes.Object, + new[] {types.XamlIlTypes.Object}, name + "!Getter", false, true, false); + if (getter != null) + { + getter.Generator + .Ldarg_0() + .Castclass(property.Getter.DeclaringType) + .EmitCall(property.Getter); + if (property.Getter.ReturnType.IsValueType) + getter.Generator.Box(property.Getter.ReturnType); + getter.Generator.Ret(); + } + + var setter = property.Setter == null ? + null : + _builder.DefineMethod(types.XamlIlTypes.Void, + new[] {types.XamlIlTypes.Object, types.XamlIlTypes.Object}, + name + "!Setter", false, true, false); + if (setter != null) + { + setter.Generator + .Ldarg_0() + .Castclass(property.Setter.DeclaringType) + .Ldarg(1); + if (property.Setter.Parameters[0].IsValueType) + setter.Generator.Unbox_Any(property.Setter.Parameters[0]); + else + setter.Generator.Castclass(property.Setter.Parameters[0]); + setter.Generator + .EmitCall(property.Setter, true) + .Ret(); + } + + var get = _builder.DefineMethod(types.IPropertyInfo, Array.Empty(), + name + "!Property", true, true, false); + + + var ctor = types.ClrPropertyInfo.Constructors.First(c => + c.Parameters.Count == 3 && c.IsStatic == false); + + var cacheMiss = get.Generator.DefineLabel(); + get.Generator + .Ldsfld(field) + .Brfalse(cacheMiss) + .Ldsfld(field) + .Ret() + .MarkLabel(cacheMiss) + .Ldstr(property.Name); + + void EmitFunc(IXamlIlEmitter emitter, IXamlIlMethod method, IXamlIlType del) + { + if (method == null) + emitter.Ldnull(); + else + { + emitter + .Ldnull() + .Ldftn(method) + .Newobj(del.Constructors.First(c => + c.Parameters.Count == 2 && + c.Parameters[0].Equals(context.Configuration.WellKnownTypes.Object))); + } + } + + EmitFunc(get.Generator, getter, ctor.Parameters[1]); + EmitFunc(get.Generator, setter, ctor.Parameters[2]); + get.Generator + .Newobj(ctor) + .Stsfld(field) + .Ldsfld(field) + .Ret(); + + lst.Add((property, get)); + return get; + } + + codeGen.EmitCall(Get()); + return types.IPropertyInfo; + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github b/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github index 610cda30c6..3ea474b672 160000 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github @@ -1 +1 @@ -Subproject commit 610cda30c69e32e83c8235060606480904c937bc +Subproject commit 3ea474b672ff63629300c36a9644caac2b74a1f2 diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs index 5398e76f63..913dd754f1 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs @@ -7,6 +7,7 @@ using System.Runtime.CompilerServices; using Avalonia.Controls; using Avalonia.Controls.Presenters; using Avalonia.Data.Converters; +using Avalonia.Data.Core; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Media; @@ -234,6 +235,17 @@ namespace Avalonia.Markup.Xaml.UnitTests Assert.Equal(100, XamlIlBugTestsStaticClassWithAttachedProperty.GetTestInt(tb)); } } + + [Fact] + public void Provide_Value_Target_Should_Provide_Clr_Property_Info() + { + var parsed = AvaloniaXamlLoader.Parse(@" +", typeof(XamlIlClassWithClrPropertyWithValue).Assembly); + Assert.Equal(6, parsed.Count); + } } public class XamlIlBugTestsEventHandlerCodeBehind : Window @@ -314,4 +326,22 @@ namespace Avalonia.Markup.Xaml.UnitTests return (int)control.GetValue(TestIntProperty); } } + + public class XamlIlCheckClrPropertyInfoExtension + { + public string ExpectedPropertyName { get; set; } + + public object ProvideValue(IServiceProvider prov) + { + var pvt = prov.GetService(); + var info = (ClrPropertyInfo)pvt.TargetProperty; + var v = (int)info.Get(pvt.TargetObject); + return v + 1; + } + } + + public class XamlIlClassWithClrPropertyWithValue + { + public int Count { get; set; }= 5; + } }