Browse Source

Added IPropertyInfo and use it in IProvideValueTarget when possible

property-path
Nikita Tsukanov 7 years ago
parent
commit
c222070d84
  1. 8
      src/Avalonia.Base/AvaloniaProperty.cs
  2. 70
      src/Avalonia.Base/Data/Core/ClrPropertyInfo.cs
  3. 11
      src/Avalonia.Base/Data/Core/IPropertyInfo.cs
  4. 9
      src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
  5. 2
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  6. 11
      src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs
  7. 6
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompiler.cs
  8. 21
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompilerConfiguration.cs
  9. 2
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs
  10. 42
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
  11. 14
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs
  12. 147
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlClrPropertyInfoHelper.cs
  13. 2
      src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github
  14. 30
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs

8
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
/// <summary>
/// Base class for avalonia properties.
/// </summary>
public class AvaloniaProperty : IEquatable<AvaloniaProperty>
public class AvaloniaProperty : IEquatable<AvaloniaProperty>, IPropertyInfo
{
/// <summary>
/// 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);
}
/// <summary>
/// Class representing the <see cref="AvaloniaProperty.UnsetValue"/>.

70
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<object, object> _getter;
private readonly Action<object, object> _setter;
public ClrPropertyInfo(string name, Func<object, object> getter, Action<object, object> 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<object, object> 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<Action<object, object>>(
Expression.Call(Expression.Convert(target, info.DeclaringType), info.SetMethod,
Expression.Convert(value, info.SetMethod.GetParameters()[0].ParameterType)),
target, value)
.Compile();
}
static Func<object, object> CreateGetter(PropertyInfo info)
{
if (info.GetMethod == null)
return null;
var target = Expression.Parameter(typeof(object), "target");
return Expression.Lambda<Func<object, object>>(
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))
{
}
}
}

11
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; }
}
}

9
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",

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

@ -38,6 +38,7 @@
<Compile Include="Templates\TemplateContent.cs" />
<Compile Include="Templates\TreeDataTemplate.cs" />
<Compile Include="XamlIl\AvaloniaXamlIlRuntimeCompiler.cs" />
<Compile Include="XamlIl\CompilerExtensions\AvaloniaXamlIlCompilerConfiguration.cs" />
<Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaBindingExtensionHackTransformer.cs" />
<Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlAvaloniaPropertyResolver.cs" />
<Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlConstructorServiceProviderTransformer.cs" />
@ -55,6 +56,7 @@
<Compile Include="XamlIl\CompilerExtensions\Transformers\IgnoredDirectivesTransformer.cs" />
<Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlSelectorTransformer.cs" />
<Compile Include="XamlIl\CompilerExtensions\Transformers\XNameTransformer.cs" />
<Compile Include="XamlIl\CompilerExtensions\XamlIlClrPropertyInfoHelper.cs" />
<Compile Include="XamlIl\Runtime\IAvaloniaXamlIlParentStackProvider.cs" />
<Compile Include="XamlIl\Runtime\IAvaloniaXamlIlXmlNamespaceInfoProviderV1.cs" />
<Compile Include="XamlIl\Runtime\XamlIlRuntimeHelpers.cs" />

11
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);
}

6
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;

21
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);
}
}
}

2
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;

42
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<AvaloniaXamlIlWellKnownTypes>(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<AvaloniaXamlIlWellKnownTypes>(out var rv))
return rv;
ctx.SetItem(rv = new AvaloniaXamlIlWellKnownTypes(ctx.Configuration));
return rv;
}
}

14
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<XamlIlClrPropertyInfoEmitter>()
.Emit(context, emitter, foundClr);
return true;
}
public static bool Emit(XamlIlEmitContext context, IXamlIlEmitter emitter, XamlIlAstClrProperty property)
{
if (property is IXamlIlAvaloniaProperty ap)

147
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<string, List<(IXamlIlProperty prop, IXamlIlMethod get)>> _fields
= new Dictionary<string, List<(IXamlIlProperty prop, IXamlIlMethod get)>>();
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<IXamlIlType>(),
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;
}
}
}

2
src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github

@ -1 +1 @@
Subproject commit 610cda30c69e32e83c8235060606480904c937bc
Subproject commit 3ea474b672ff63629300c36a9644caac2b74a1f2

30
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<XamlIlClassWithClrPropertyWithValue>(@"
<XamlIlClassWithClrPropertyWithValue
xmlns='clr-namespace:Avalonia.Markup.Xaml.UnitTests'
Count='{XamlIlCheckClrPropertyInfo ExpectedPropertyName=Count}'
/>", 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<IProvideValueTarget>();
var info = (ClrPropertyInfo)pvt.TargetProperty;
var v = (int)info.Get(pvt.TargetObject);
return v + 1;
}
}
public class XamlIlClassWithClrPropertyWithValue
{
public int Count { get; set; }= 5;
}
}

Loading…
Cancel
Save