Browse Source
* test: Automatic RoutedEvent Handler Generation * feat: Every RoutedEvent should be usable as Attached Event * fix: Namespace * fix: Address review * feat: Handle Preview event * test: Handle Preview event * fix: Address Review reverted Preview feture * fix: Throw On Fatal * fix: Error Codepull/15929/head
committed by
GitHub
5 changed files with 223 additions and 4 deletions
@ -0,0 +1,118 @@ |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using XamlX.Ast; |
|||
using XamlX.Emit; |
|||
using XamlX.IL; |
|||
using XamlX.Transform; |
|||
using XamlX.TypeSystem; |
|||
|
|||
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers; |
|||
|
|||
internal class AvaloniaXamlIlTransformRoutedEvent : IXamlAstTransformer |
|||
{ |
|||
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) |
|||
{ |
|||
if (node is XamlAstNamePropertyReference prop |
|||
&& prop.TargetType is XamlAstClrTypeReference targetRef |
|||
&& prop.DeclaringType is XamlAstClrTypeReference declaringRef) |
|||
{ |
|||
var xkt = context.GetAvaloniaTypes(); |
|||
var interactiveType = xkt.Interactivity.Interactive; |
|||
var routedEventType = xkt.Interactivity.RoutedEvent; |
|||
var AddHandlerT = xkt.Interactivity.AddHandlerT; |
|||
|
|||
if (interactiveType.IsAssignableFrom(targetRef.Type)) |
|||
{ |
|||
var eventName = $"{prop.Name}Event"; |
|||
if (declaringRef.Type.GetAllFields().FirstOrDefault(f => f.IsStatic && f.Name == eventName) is { } eventField) |
|||
{ |
|||
if (routedEventType.IsAssignableFrom(eventField.FieldType)) |
|||
{ |
|||
var instance = new XamlAstClrProperty(prop |
|||
, prop.Name |
|||
, targetRef.Type |
|||
, null |
|||
); |
|||
instance.Setters.Add(new XamlDirectCallAddHandler(eventField, |
|||
targetRef.Type, |
|||
xkt.Interactivity.AddHandler, |
|||
xkt.Interactivity.RoutedEventHandler |
|||
) |
|||
); |
|||
if (eventField.FieldType.GenericArguments?.Count == 1) |
|||
{ |
|||
var agrument = eventField.FieldType.GenericArguments[0]; |
|||
if (!agrument.Equals(xkt.Interactivity.RoutedEventArgs)) |
|||
{ |
|||
instance.Setters.Add(new XamlDirectCallAddHandler(eventField, |
|||
targetRef.Type, |
|||
xkt.Interactivity.AddHandlerT.MakeGenericMethod([agrument]), |
|||
xkt.EventHandlerT.MakeGenericType(agrument) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
return instance; |
|||
} |
|||
else |
|||
{ |
|||
context.ReportDiagnostic(new XamlX.XamlDiagnostic( |
|||
AvaloniaXamlDiagnosticCodes.TransformError, |
|||
XamlX.XamlDiagnosticSeverity.Error, |
|||
$"Event definition {prop.Name} found, but its type {eventField.FieldType.GetFqn()} is not compatible with RoutedEvent.", |
|||
node)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
return node; |
|||
} |
|||
|
|||
private sealed class XamlDirectCallAddHandler : IXamlILOptimizedEmitablePropertySetter |
|||
{ |
|||
private readonly IXamlField _eventField; |
|||
private readonly IXamlType _declaringType; |
|||
private readonly IXamlMethod _addMethod; |
|||
|
|||
public XamlDirectCallAddHandler(IXamlField eventField, |
|||
IXamlType declaringType, |
|||
IXamlMethod addMethod, |
|||
IXamlType routedEventHandler |
|||
) |
|||
{ |
|||
Parameters = [routedEventHandler]; |
|||
_eventField = eventField; |
|||
_declaringType = declaringType; |
|||
_addMethod = addMethod; |
|||
} |
|||
|
|||
public IXamlType TargetType => _declaringType; |
|||
public PropertySetterBinderParameters BinderParameters { get; } = new PropertySetterBinderParameters(); |
|||
public IReadOnlyList<IXamlType> Parameters { get; } |
|||
|
|||
public IReadOnlyList<IXamlCustomAttribute> CustomAttributes => []; |
|||
|
|||
public void Emit(IXamlILEmitter emitter) |
|||
=> emitter.EmitCall(_addMethod, true); |
|||
|
|||
public void EmitWithArguments(XamlEmitContextWithLocals<IXamlILEmitter, XamlILNodeEmitResult> context, |
|||
IXamlILEmitter emitter, |
|||
IReadOnlyList<IXamlAstValueNode> arguments) |
|||
{ |
|||
|
|||
using (var loc = emitter.LocalsPool.GetLocal(_declaringType)) |
|||
emitter |
|||
.Ldloc(loc.Local); |
|||
|
|||
emitter.Ldfld(_eventField); |
|||
|
|||
for (var i = 0; i < arguments.Count; ++i) |
|||
context.Emit(arguments[i], emitter, Parameters[i]); |
|||
|
|||
emitter.Ldc_I4(5); |
|||
emitter.Ldc_I4(0); |
|||
|
|||
emitter.EmitCall(_addMethod, true); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue