I'm trying to subscribe to a runtime event dynamically using generics and reflection. Purpose is to be able to subscribe to e.g. the PointerReleased
event of a Grid
using XAML and execute a command when the event is raised.
<Grid namespace:CommandExtension.Event="PointerReleased"
...>
</Grid>
So far i have the following code:
var eInfo = d.GetType().GetRuntimeEvent(e.NewValue.ToString());
if (eInfo != null)
{
// Get the type of the event handler
var handlerType = eInfo.EventHandlerType;
// Create the add handler using CreateAddFunction and reflection
var addFunc = typeof(CommandExtension).GetMethod(nameof(CreateAddFunction), BindingFlags.Instance | BindingFlags.NonPublic)
.MakeGenericMethod(handlerType);
dynamic add = addFunc.Invoke(new CommandExtension(), new object[] { eInfo, d });
// Create the remove handler that is stored for removing the handler if the event changes
Action<EventRegistrationToken> remove = (a) => { eInfo.RemoveMethod.Invoke(eInfo, new object[] { a }); };
// Create the handler
var action = new Action<object, RoutedEventArgs>(CommandInvoke);
var invoke = action.GetType().GetMethod("Invoke");
var expressionParams = handlerType.GetMethod("Invoke").GetParameters().Select(p => Expression.Parameter(p.ParameterType)).ToArray();
var handler = Expression.Lambda(handlerType,
Expression.Call(Expression.Constant(action),
invoke,
expressionParams[0], expressionParams[1]),
expressionParams)
.Compile();
// Add the handler
var runtimeMarshalAdd = typeof(WindowsRuntimeMarshal).GetMethod("AddEventHandler", BindingFlags.Static | BindingFlags.Public)
.MakeGenericMethod(handlerType);
runtimeMarshalAdd.Invoke(null, new object[] { add, remove, handler });
}
// T is the type of the event handler e.g. RoutedEventHandler
private Func<T, EventRegistrationToken> CreateAddFunction<T>(EventInfo eInfo, DependencyObject d)
{
return new Func<T, EventRegistrationToken>((a) => { return (EventRegistrationToken)eInfo.AddMethod.Invoke(d, new object[] { a }); });
}
Now whenever runtimeMarshalAdd.Invoke
is invoked an exception stating that the operation would not be available:
Exception thrown: 'System.InvalidOperationException' in mscorlib.ni.dll ("The API 'System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal.AddEventHandler[PointerEventHandler]
(System.Func'2[Windows.UI.Xaml.Input.PointerEventHandler,System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken], System.Action'1[System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken], Windows.UI.Xaml.Input.PointerEventHandler)' cannot be used on the current platform. See http://ift.tt/1mu4Xh2 for more information.")
However doing the same stuff non-generic works.
Button b = new Button();
var eInfo = b.GetType().GetRuntimeEvent("PointerReleased");
Func<PointerEventHandler, EventRegistrationToken> add = (a) => { return (EventRegistrationToken)eInfo.AddMethod.Invoke(b, new object[] { a }); };
Action<EventRegistrationToken> remove = (a) => { eInfo.RemoveMethod.Invoke(eInfo, new object[] { a }); };
PointerEventHandler handler = CommandInvoke;
WindowsRuntimeMarshal.AddEventHandler(add, remove, handler);
Am i missing something in my attempt of adding the handler?
Aucun commentaire:
Enregistrer un commentaire