17 changed files with 707 additions and 396 deletions
@ -0,0 +1,67 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
using Avalonia.Data; |
||||
|
using Avalonia.Data.Core.Plugins; |
||||
|
|
||||
|
namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings |
||||
|
{ |
||||
|
class ArrayElementPlugin : IPropertyAccessorPlugin |
||||
|
{ |
||||
|
private readonly int[] _indices; |
||||
|
private readonly Type _elementType; |
||||
|
|
||||
|
public ArrayElementPlugin(int[] indices, Type elementType) |
||||
|
{ |
||||
|
_indices = indices; |
||||
|
_elementType = elementType; |
||||
|
} |
||||
|
|
||||
|
public bool Match(object obj, string propertyName) |
||||
|
{ |
||||
|
throw new InvalidOperationException("The ArrayElementPlugin does not support dynamic matching"); |
||||
|
} |
||||
|
|
||||
|
public IPropertyAccessor Start(WeakReference reference, string propertyName) |
||||
|
{ |
||||
|
return new Accessor(reference, _indices, _elementType); |
||||
|
} |
||||
|
|
||||
|
class Accessor : PropertyAccessorBase |
||||
|
{ |
||||
|
private readonly int[] _indices; |
||||
|
private readonly WeakReference _reference; |
||||
|
|
||||
|
public Accessor(WeakReference reference, int[] indices, Type elementType) |
||||
|
{ |
||||
|
_reference = reference; |
||||
|
_indices = indices; |
||||
|
PropertyType = elementType; |
||||
|
} |
||||
|
|
||||
|
public override Type PropertyType { get; } |
||||
|
|
||||
|
public override object Value => _reference.Target is Array arr ? arr.GetValue(_indices) : null; |
||||
|
|
||||
|
public override bool SetValue(object value, BindingPriority priority) |
||||
|
{ |
||||
|
if (_reference.Target is Array arr) |
||||
|
{ |
||||
|
arr.SetValue(value, _indices); |
||||
|
return true; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
protected override void SubscribeCore() |
||||
|
{ |
||||
|
PublishValue(Value); |
||||
|
} |
||||
|
|
||||
|
protected override void UnsubscribeCore() |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -1,255 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Collections.Specialized; |
|
||||
using System.ComponentModel; |
|
||||
using System.Diagnostics; |
|
||||
using System.Runtime.CompilerServices; |
|
||||
using System.Text; |
|
||||
using Avalonia.Data.Core; |
|
||||
using Avalonia.Reactive; |
|
||||
using Avalonia.Utilities; |
|
||||
|
|
||||
namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings |
|
||||
{ |
|
||||
public static class NotifyingPropertyInfoHelpers |
|
||||
{ |
|
||||
public static INotifyingPropertyInfo CreateINPCPropertyInfo(IPropertyInfo basePropertyInfo) |
|
||||
=> new INPCPropertyInfo(basePropertyInfo); |
|
||||
|
|
||||
public static INotifyingPropertyInfo CreateAvaloniaPropertyInfo(AvaloniaProperty property) |
|
||||
=> new AvaloniaPropertyInfo(property); |
|
||||
|
|
||||
public static INotifyingPropertyInfo CreateIndexerPropertyInfo(IPropertyInfo basePropertyInfo, int argument) |
|
||||
=> new IndexerInfo(basePropertyInfo, argument); |
|
||||
} |
|
||||
|
|
||||
public interface INotifyingPropertyInfo : IPropertyInfo |
|
||||
{ |
|
||||
void OnPropertyChanged(object target, EventHandler handler); |
|
||||
void RemoveListener(object target, EventHandler handler); |
|
||||
} |
|
||||
|
|
||||
internal abstract class NotifyingPropertyInfoBase : INotifyingPropertyInfo |
|
||||
{ |
|
||||
private readonly IPropertyInfo _base; |
|
||||
protected readonly ConditionalWeakTable<object, EventHandler> _changedHandlers = new ConditionalWeakTable<object, EventHandler>(); |
|
||||
|
|
||||
public NotifyingPropertyInfoBase(IPropertyInfo baseProperty) |
|
||||
{ |
|
||||
_base = baseProperty; |
|
||||
} |
|
||||
|
|
||||
public string Name => _base.Name; |
|
||||
|
|
||||
public bool CanSet => _base.CanSet; |
|
||||
|
|
||||
public bool CanGet => _base.CanGet; |
|
||||
|
|
||||
public Type PropertyType => _base.PropertyType; |
|
||||
|
|
||||
public object Get(object target) |
|
||||
{ |
|
||||
return _base.Get(target); |
|
||||
} |
|
||||
|
|
||||
public void Set(object target, object value) |
|
||||
{ |
|
||||
_base.Set(target, value); |
|
||||
} |
|
||||
|
|
||||
public void OnPropertyChanged(object target, EventHandler handler) |
|
||||
{ |
|
||||
if (ValidateTargetType(target)) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
if (_changedHandlers.TryGetValue(target, out var value)) |
|
||||
{ |
|
||||
_changedHandlers.Remove(target); |
|
||||
_changedHandlers.Add(target, (EventHandler)Delegate.Combine(value, handler)); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
_changedHandlers.Add(target, handler); |
|
||||
SubscribeToChangesForNewTarget(target); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
protected abstract bool ValidateTargetType(object target); |
|
||||
|
|
||||
protected abstract void SubscribeToChangesForNewTarget(object target); |
|
||||
|
|
||||
protected abstract void UnsubscribeToChangesForTarget(object target); |
|
||||
|
|
||||
protected bool TryGetHandlersForTarget(object target, out EventHandler handlers) |
|
||||
=> _changedHandlers.TryGetValue(target, out handlers); |
|
||||
|
|
||||
public void RemoveListener(object target, EventHandler handler) |
|
||||
{ |
|
||||
if (!ValidateTargetType(target)) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
if (_changedHandlers.TryGetValue(target, out var value)) |
|
||||
{ |
|
||||
_changedHandlers.Remove(target); |
|
||||
EventHandler modified = (EventHandler)Delegate.Remove(value, handler); |
|
||||
if (modified != null) |
|
||||
{ |
|
||||
_changedHandlers.Add(target, modified); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
UnsubscribeToChangesForTarget(target); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
internal class INPCPropertyInfo : NotifyingPropertyInfoBase |
|
||||
{ |
|
||||
public INPCPropertyInfo(IPropertyInfo baseProperty) |
|
||||
:base(baseProperty) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
void OnNotifyPropertyChanged(object sender, PropertyChangedEventArgs e) |
|
||||
{ |
|
||||
if (Name == e.PropertyName && TryGetHandlersForTarget(sender, out var handlers)) |
|
||||
{ |
|
||||
handlers(sender, EventArgs.Empty); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
protected override bool ValidateTargetType(object target) |
|
||||
{ |
|
||||
return target is INotifyPropertyChanged; |
|
||||
} |
|
||||
|
|
||||
protected override void SubscribeToChangesForNewTarget(object target) |
|
||||
{ |
|
||||
if (target is INotifyPropertyChanged inpc) |
|
||||
{ |
|
||||
WeakEventHandlerManager.Subscribe<INotifyPropertyChanged, PropertyChangedEventArgs, INPCPropertyInfo>( |
|
||||
inpc, |
|
||||
nameof(INotifyPropertyChanged.PropertyChanged), |
|
||||
OnNotifyPropertyChanged); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
protected override void UnsubscribeToChangesForTarget(object target) |
|
||||
{ |
|
||||
if (target is INotifyPropertyChanged) |
|
||||
{ |
|
||||
WeakEventHandlerManager.Unsubscribe<PropertyChangedEventArgs, INPCPropertyInfo>( |
|
||||
target, |
|
||||
nameof(INotifyPropertyChanged.PropertyChanged), |
|
||||
OnNotifyPropertyChanged); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
internal class AvaloniaPropertyInfo : NotifyingPropertyInfoBase |
|
||||
{ |
|
||||
private readonly AvaloniaProperty _base; |
|
||||
|
|
||||
public AvaloniaPropertyInfo(AvaloniaProperty baseProperty) |
|
||||
:base(baseProperty) |
|
||||
{ |
|
||||
_base = baseProperty; |
|
||||
} |
|
||||
|
|
||||
protected override void SubscribeToChangesForNewTarget(object target) |
|
||||
{ |
|
||||
IAvaloniaObject obj = (IAvaloniaObject)target; |
|
||||
obj.PropertyChanged += OnPropertyChanged; |
|
||||
} |
|
||||
|
|
||||
private void OnPropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e) |
|
||||
{ |
|
||||
if (_base == e.Property && TryGetHandlersForTarget(sender, out var handlers)) |
|
||||
{ |
|
||||
handlers(sender, EventArgs.Empty); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
protected override void UnsubscribeToChangesForTarget(object target) |
|
||||
{ |
|
||||
((IAvaloniaObject)target).PropertyChanged -= OnPropertyChanged; |
|
||||
} |
|
||||
|
|
||||
protected override bool ValidateTargetType(object target) |
|
||||
{ |
|
||||
return target is IAvaloniaObject; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
internal class IndexerInfo : INPCPropertyInfo |
|
||||
{ |
|
||||
private int _index; |
|
||||
|
|
||||
public IndexerInfo(IPropertyInfo baseProperty, int indexerArgument) : base(baseProperty) |
|
||||
{ |
|
||||
_index = indexerArgument; |
|
||||
} |
|
||||
|
|
||||
protected override void SubscribeToChangesForNewTarget(object target) |
|
||||
{ |
|
||||
base.SubscribeToChangesForNewTarget(target); |
|
||||
if (target is INotifyCollectionChanged incc) |
|
||||
{ |
|
||||
WeakEventHandlerManager.Subscribe<INotifyCollectionChanged, NotifyCollectionChangedEventArgs, IndexerInfo>( |
|
||||
incc, |
|
||||
nameof(INotifyCollectionChanged.CollectionChanged), |
|
||||
OnNotifyCollectionChanged); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
protected override void UnsubscribeToChangesForTarget(object target) |
|
||||
{ |
|
||||
base.UnsubscribeToChangesForTarget(target); |
|
||||
if (target is INotifyCollectionChanged) |
|
||||
{ |
|
||||
WeakEventHandlerManager.Unsubscribe<NotifyCollectionChangedEventArgs, IndexerInfo>( |
|
||||
target, |
|
||||
nameof(INotifyCollectionChanged.CollectionChanged), |
|
||||
OnNotifyCollectionChanged); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void OnNotifyCollectionChanged(object sender, NotifyCollectionChangedEventArgs args) |
|
||||
{ |
|
||||
if (ShouldNotifyListeners(args) && TryGetHandlersForTarget(sender, out var handlers)) |
|
||||
{ |
|
||||
handlers(sender, EventArgs.Empty); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
bool ShouldNotifyListeners(NotifyCollectionChangedEventArgs e) |
|
||||
{ |
|
||||
switch (e.Action) |
|
||||
{ |
|
||||
case NotifyCollectionChangedAction.Add: |
|
||||
return _index >= e.NewStartingIndex; |
|
||||
case NotifyCollectionChangedAction.Remove: |
|
||||
return _index >= e.OldStartingIndex; |
|
||||
case NotifyCollectionChangedAction.Replace: |
|
||||
return _index >= e.NewStartingIndex && |
|
||||
_index < e.NewStartingIndex + e.NewItems.Count; |
|
||||
case NotifyCollectionChangedAction.Move: |
|
||||
return (_index >= e.NewStartingIndex && |
|
||||
_index < e.NewStartingIndex + e.NewItems.Count) || |
|
||||
(_index >= e.OldStartingIndex && |
|
||||
_index < e.OldStartingIndex + e.OldItems.Count); |
|
||||
case NotifyCollectionChangedAction.Reset: |
|
||||
return true; |
|
||||
} |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
protected override bool ValidateTargetType(object target) |
|
||||
=> base.ValidateTargetType(target) || target is INotifyCollectionChanged; |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,230 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Collections.Specialized; |
||||
|
using System.ComponentModel; |
||||
|
using System.Text; |
||||
|
using Avalonia.Data; |
||||
|
using Avalonia.Data.Core; |
||||
|
using Avalonia.Data.Core.Plugins; |
||||
|
using Avalonia.Utilities; |
||||
|
|
||||
|
namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings |
||||
|
{ |
||||
|
public static class PropertyInfoAccessorFactory |
||||
|
{ |
||||
|
public static IPropertyAccessor CreateInpcPropertyAccessor(WeakReference target, IPropertyInfo property) |
||||
|
=> new InpcPropertyAccessor(target, property); |
||||
|
|
||||
|
public static IPropertyAccessor CreateAvaloniaPropertyAccessor(WeakReference target, IPropertyInfo property) |
||||
|
=> new AvaloniaPropertyAccessor(new WeakReference<AvaloniaObject>((AvaloniaObject)target.Target), (AvaloniaProperty)property); |
||||
|
|
||||
|
public static IPropertyAccessor CreateIndexerPropertyAccessor(WeakReference target, IPropertyInfo property, int argument) |
||||
|
=> new IndexerAccessor(target, property, argument); |
||||
|
} |
||||
|
|
||||
|
internal class AvaloniaPropertyAccessor : PropertyAccessorBase |
||||
|
{ |
||||
|
private readonly WeakReference<AvaloniaObject> _reference; |
||||
|
private readonly AvaloniaProperty _property; |
||||
|
private IDisposable _subscription; |
||||
|
|
||||
|
public AvaloniaPropertyAccessor(WeakReference<AvaloniaObject> reference, AvaloniaProperty property) |
||||
|
{ |
||||
|
Contract.Requires<ArgumentNullException>(reference != null); |
||||
|
Contract.Requires<ArgumentNullException>(property != null); |
||||
|
|
||||
|
_reference = reference; |
||||
|
_property = property; |
||||
|
} |
||||
|
|
||||
|
public AvaloniaObject Instance |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
_reference.TryGetTarget(out var result); |
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public override Type PropertyType => _property.PropertyType; |
||||
|
public override object Value => Instance?.GetValue(_property); |
||||
|
|
||||
|
public override bool SetValue(object value, BindingPriority priority) |
||||
|
{ |
||||
|
if (!_property.IsReadOnly) |
||||
|
{ |
||||
|
Instance.SetValue(_property, value, priority); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
protected override void SubscribeCore() |
||||
|
{ |
||||
|
_subscription = Instance?.GetObservable(_property).Subscribe(PublishValue); |
||||
|
} |
||||
|
|
||||
|
protected override void UnsubscribeCore() |
||||
|
{ |
||||
|
_subscription?.Dispose(); |
||||
|
_subscription = null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal class InpcPropertyAccessor : PropertyAccessorBase |
||||
|
{ |
||||
|
protected readonly WeakReference _reference; |
||||
|
private readonly IPropertyInfo _property; |
||||
|
|
||||
|
public InpcPropertyAccessor(WeakReference reference, IPropertyInfo property) |
||||
|
{ |
||||
|
Contract.Requires<ArgumentNullException>(reference != null); |
||||
|
Contract.Requires<ArgumentNullException>(property != null); |
||||
|
|
||||
|
_reference = reference; |
||||
|
_property = property; |
||||
|
} |
||||
|
|
||||
|
public override Type PropertyType => _property.PropertyType; |
||||
|
|
||||
|
public override object Value |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
var o = _reference.Target; |
||||
|
return (o != null) ? _property.Get(o) : null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public override bool SetValue(object value, BindingPriority priority) |
||||
|
{ |
||||
|
if (_property.CanSet && _reference.IsAlive) |
||||
|
{ |
||||
|
_property.Set(_reference.Target, value); |
||||
|
|
||||
|
SendCurrentValue(); |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
void OnNotifyPropertyChanged(object sender, PropertyChangedEventArgs e) |
||||
|
{ |
||||
|
if (e.PropertyName == _property.Name || string.IsNullOrEmpty(e.PropertyName)) |
||||
|
{ |
||||
|
SendCurrentValue(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected override void SubscribeCore() |
||||
|
{ |
||||
|
SendCurrentValue(); |
||||
|
SubscribeToChanges(); |
||||
|
} |
||||
|
|
||||
|
protected override void UnsubscribeCore() |
||||
|
{ |
||||
|
var inpc = _reference.Target as INotifyPropertyChanged; |
||||
|
|
||||
|
if (inpc != null) |
||||
|
{ |
||||
|
WeakEventHandlerManager.Unsubscribe<PropertyChangedEventArgs, InpcPropertyAccessor>( |
||||
|
inpc, |
||||
|
nameof(INotifyPropertyChanged.PropertyChanged), |
||||
|
OnNotifyPropertyChanged); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected void SendCurrentValue() |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
var value = Value; |
||||
|
PublishValue(value); |
||||
|
} |
||||
|
catch { } |
||||
|
} |
||||
|
|
||||
|
private void SubscribeToChanges() |
||||
|
{ |
||||
|
var inpc = _reference.Target as INotifyPropertyChanged; |
||||
|
|
||||
|
if (inpc != null) |
||||
|
{ |
||||
|
WeakEventHandlerManager.Subscribe<INotifyPropertyChanged, PropertyChangedEventArgs, InpcPropertyAccessor>( |
||||
|
inpc, |
||||
|
nameof(INotifyPropertyChanged.PropertyChanged), |
||||
|
OnNotifyPropertyChanged); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal class IndexerAccessor : InpcPropertyAccessor |
||||
|
{ |
||||
|
private int _index; |
||||
|
|
||||
|
public IndexerAccessor(WeakReference target, IPropertyInfo basePropertyInfo, int argument) |
||||
|
:base(target, basePropertyInfo) |
||||
|
{ |
||||
|
_index = argument; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
protected override void SubscribeCore() |
||||
|
{ |
||||
|
base.SubscribeCore(); |
||||
|
if (_reference.Target is INotifyCollectionChanged incc) |
||||
|
{ |
||||
|
WeakEventHandlerManager.Subscribe<INotifyCollectionChanged, NotifyCollectionChangedEventArgs, IndexerAccessor>( |
||||
|
incc, |
||||
|
nameof(INotifyCollectionChanged.CollectionChanged), |
||||
|
OnNotifyCollectionChanged); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected override void UnsubscribeCore() |
||||
|
{ |
||||
|
base.UnsubscribeCore(); |
||||
|
if (_reference.Target is INotifyCollectionChanged incc) |
||||
|
{ |
||||
|
WeakEventHandlerManager.Unsubscribe<NotifyCollectionChangedEventArgs, IndexerAccessor>( |
||||
|
incc, |
||||
|
nameof(INotifyCollectionChanged.CollectionChanged), |
||||
|
OnNotifyCollectionChanged); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void OnNotifyCollectionChanged(object sender, NotifyCollectionChangedEventArgs args) |
||||
|
{ |
||||
|
if (ShouldNotifyListeners(args)) |
||||
|
{ |
||||
|
SendCurrentValue(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
bool ShouldNotifyListeners(NotifyCollectionChangedEventArgs e) |
||||
|
{ |
||||
|
switch (e.Action) |
||||
|
{ |
||||
|
case NotifyCollectionChangedAction.Add: |
||||
|
return _index >= e.NewStartingIndex; |
||||
|
case NotifyCollectionChangedAction.Remove: |
||||
|
return _index >= e.OldStartingIndex; |
||||
|
case NotifyCollectionChangedAction.Replace: |
||||
|
return _index >= e.NewStartingIndex && |
||||
|
_index < e.NewStartingIndex + e.NewItems.Count; |
||||
|
case NotifyCollectionChangedAction.Move: |
||||
|
return (_index >= e.NewStartingIndex && |
||||
|
_index < e.NewStartingIndex + e.NewItems.Count) || |
||||
|
(_index >= e.OldStartingIndex && |
||||
|
_index < e.OldStartingIndex + e.OldItems.Count); |
||||
|
case NotifyCollectionChangedAction.Reset: |
||||
|
return true; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,103 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers; |
||||
|
using XamlIl.Ast; |
||||
|
using XamlIl.Transform; |
||||
|
using XamlIl.TypeSystem; |
||||
|
|
||||
|
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions |
||||
|
{ |
||||
|
class XamlIlPropertyInfoAccessorFactoryEmitter |
||||
|
{ |
||||
|
private bool _indexerClosureTypeInitialized = false; |
||||
|
private readonly IXamlIlTypeBuilder _indexerClosureType; |
||||
|
public XamlIlPropertyInfoAccessorFactoryEmitter(IXamlIlTypeBuilder indexerClosureType) |
||||
|
{ |
||||
|
_indexerClosureType = indexerClosureType; |
||||
|
} |
||||
|
|
||||
|
public IXamlIlType EmitLoadInpcPropertyAccessorFactory(XamlIlEmitContext context, IXamlIlEmitter codeGen) |
||||
|
{ |
||||
|
codeGen.Ldnull(); |
||||
|
EmitLoadPropertyAccessorFactory(context, codeGen, context.GetAvaloniaTypes().PropertyInfoAccessorFactory, "CreateInpcPropertyAccessor"); |
||||
|
return EmitCreateAccessorFactoryDelegate(context, codeGen); |
||||
|
} |
||||
|
|
||||
|
public IXamlIlType EmitLoadAvaloniaPropertyAccessorFactory(XamlIlEmitContext context, IXamlIlEmitter codeGen) |
||||
|
{ |
||||
|
codeGen.Ldnull(); |
||||
|
EmitLoadPropertyAccessorFactory(context, codeGen, context.GetAvaloniaTypes().PropertyInfoAccessorFactory, "CreateAvaloniaPropertyAccessor"); |
||||
|
return EmitCreateAccessorFactoryDelegate(context, codeGen); |
||||
|
} |
||||
|
|
||||
|
private void EmitLoadPropertyAccessorFactory(XamlIlEmitContext context, IXamlIlEmitter codeGen, IXamlIlType type, string accessorFactoryName) |
||||
|
{ |
||||
|
var types = context.GetAvaloniaTypes(); |
||||
|
var weakReferenceType = context.Configuration.TypeSystem.GetType("System.WeakReference"); |
||||
|
FindMethodMethodSignature accessorFactorySignature = new FindMethodMethodSignature(accessorFactoryName, types.IPropertyAccessor, weakReferenceType, types.IPropertyInfo) |
||||
|
{ |
||||
|
IsStatic = true |
||||
|
}; |
||||
|
codeGen.Ldftn(type.GetMethod(accessorFactorySignature)); |
||||
|
} |
||||
|
|
||||
|
public IXamlIlType EmitLoadIndexerAccessorFactory(XamlIlEmitContext context, IXamlIlEmitter codeGen, IXamlIlAstValueNode value) |
||||
|
{ |
||||
|
const string indexerClosureFactoryMethodName = "CreateAccessor"; |
||||
|
var types = context.GetAvaloniaTypes(); |
||||
|
var intType = context.Configuration.TypeSystem.GetType("System.Int32"); |
||||
|
var weakReferenceType = context.Configuration.TypeSystem.GetType("System.WeakReference"); |
||||
|
if (!_indexerClosureTypeInitialized) |
||||
|
{ |
||||
|
var indexAccessorFactoryMethod = context.GetAvaloniaTypes().PropertyInfoAccessorFactory.GetMethod( |
||||
|
new FindMethodMethodSignature( |
||||
|
"CreateIndexerPropertyAccessor", |
||||
|
types.IPropertyAccessor, |
||||
|
weakReferenceType, |
||||
|
types.IPropertyInfo, |
||||
|
intType) |
||||
|
{ |
||||
|
IsStatic = true |
||||
|
}); |
||||
|
var indexField = _indexerClosureType.DefineField(intType, "_index", false, false); |
||||
|
var ctor = _indexerClosureType.DefineConstructor(false, intType); |
||||
|
ctor.Generator |
||||
|
.Ldarg_0() |
||||
|
.Stfld(indexField); |
||||
|
_indexerClosureType.DefineMethod( |
||||
|
types.IPropertyAccessor, |
||||
|
new[] { weakReferenceType, types.IPropertyInfo }, |
||||
|
indexerClosureFactoryMethodName, |
||||
|
isPublic: false, |
||||
|
isStatic: false, |
||||
|
isInterfaceImpl: false) |
||||
|
.Generator |
||||
|
.Ldarg_0() |
||||
|
.Ldarg(1) |
||||
|
.Ldfld(indexField) |
||||
|
.EmitCall(indexAccessorFactoryMethod); |
||||
|
} |
||||
|
|
||||
|
context.Emit(value, codeGen, intType); |
||||
|
codeGen.Newobj(_indexerClosureType.FindConstructor(new List<IXamlIlType> { intType })); |
||||
|
EmitLoadPropertyAccessorFactory(context, codeGen, _indexerClosureType, indexerClosureFactoryMethodName); |
||||
|
return EmitCreateAccessorFactoryDelegate(context, codeGen); |
||||
|
} |
||||
|
|
||||
|
private IXamlIlType EmitCreateAccessorFactoryDelegate(XamlIlEmitContext context, IXamlIlEmitter codeGen) |
||||
|
{ |
||||
|
var types = context.GetAvaloniaTypes(); |
||||
|
var weakReferenceType = context.Configuration.TypeSystem.GetType("System.WeakReference"); |
||||
|
var funcType = context.Configuration.TypeSystem.GetType("System.Func`3").MakeGenericType( |
||||
|
weakReferenceType, |
||||
|
types.IPropertyInfo, |
||||
|
types.IPropertyAccessor); |
||||
|
codeGen.Newobj(funcType.Constructors.First(c => |
||||
|
c.Parameters.Count == 2 && |
||||
|
c.Parameters[0].Equals(context.Configuration.WellKnownTypes.Object))); |
||||
|
return funcType; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue