diff --git a/src/Avalonia.Interactivity/EventSubscription.cs b/src/Avalonia.Interactivity/EventSubscription.cs index 9f763edcd3..ff2a28e570 100644 --- a/src/Avalonia.Interactivity/EventSubscription.cs +++ b/src/Avalonia.Interactivity/EventSubscription.cs @@ -5,8 +5,12 @@ using System; namespace Avalonia.Interactivity { + internal delegate void InvokeSignature(Delegate func, object sender, RoutedEventArgs args); + internal class EventSubscription { + public InvokeSignature RaiseHandler { get; set; } + public Delegate Handler { get; set; } public RoutingStrategies Routes { get; set; } diff --git a/src/Avalonia.Interactivity/Interactive.cs b/src/Avalonia.Interactivity/Interactive.cs index 911fc2130e..033686a8c8 100644 --- a/src/Avalonia.Interactivity/Interactive.cs +++ b/src/Avalonia.Interactivity/Interactive.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using System.Reactive.Disposables; using System.Reactive.Linq; using Avalonia.Layout; @@ -28,6 +29,10 @@ namespace Avalonia.Interactivity get { return _eventHandlers ?? (_eventHandlers = new Dictionary>()); } } + + + private static Dictionary s_invokeCache = new Dictionary(); + /// /// Adds a handler for the specified routed event. /// @@ -53,8 +58,27 @@ namespace Avalonia.Interactivity EventHandlers.Add(routedEvent, subscriptions); } + if (!s_invokeCache.TryGetValue(routedEvent.EventArgsType, out InvokeSignature raiseFunc)) + { + ParameterExpression funcParameter = Expression.Parameter(typeof(Delegate), "func"); + ParameterExpression senderParameter = Expression.Parameter(typeof(object), "sender"); + ParameterExpression argsParameter = Expression.Parameter(typeof(RoutedEventArgs), "args"); + + UnaryExpression convertedFunc = Expression.Convert(funcParameter, typeof(EventHandler<>).MakeGenericType(routedEvent.EventArgsType)); + UnaryExpression convertedArgs = Expression.Convert(argsParameter, routedEvent.EventArgsType); + + InvocationExpression invokeDelegate = Expression.Invoke(convertedFunc, senderParameter, convertedArgs); + + raiseFunc = Expression + .Lambda(invokeDelegate, funcParameter, senderParameter, argsParameter) + .Compile(); + + s_invokeCache.Add(routedEvent.EventArgsType, raiseFunc); + } + var sub = new EventSubscription { + RaiseHandler = raiseFunc, Handler = handler, Routes = routes, AlsoIfHandled = handledEventsToo, @@ -196,7 +220,7 @@ namespace Avalonia.Interactivity if (correctRoute && notFinished) { - sub.Handler.DynamicInvoke(this, e); + sub.RaiseHandler(sub.Handler, this, e); } } }