如何以编程方式将TypedEventHandler添加到RoutedEvents?

时间:2015-07-07 15:35:04

标签: c# .net windows-runtime windows-phone-8.1 windows-8.1

我正在开发一种扩展方法,但我遇到了部分问题。

这是一个想法:我想创建一个方法,它接受一个对象和一个事件的名称,等待事件被引发,然后返回它的事件args。 我使用它来避免每次在我的代码中执行类似的操作时都必须手动创建委托和内容。

注意:代码位于针对Windows8.1和Windows Phone 8.1的PCL中,因此这里没有一些反射方法。

这是我到目前为止所做的:

/// <summary>
/// Waits for an event to be raised and returns its arguments
/// </summary>
/// <typeparam name="Targs">The type of the event args to return</typeparam>
/// <param name="target">The target object that will raise the event</param>
/// <param name="eventName">The name of the event to wait</param>
/// <param name="timeout">The time limit (in millisecond) to wait for the desired event to be raised</param>
public static async Task<Targs> WaitEventAsync<Targs>(this object target, String eventName, int timeout)
    where Targs : class
{
    // Arguments check
    if (target == null) throw new ArgumentNullException("The target object can't be null");
    if (eventName == null) throw new ArgumentNullException("The event name can't be null");
    if (timeout <= 0) throw new ArgumentOutOfRangeException("The timeout must be greater than 0");

    // Get the target event
    EventInfo eventInfo = target.GetType().GetRuntimeEvent(eventName);
    if (eventInfo == null) throw new ArgumentException(String.Format("The target object doesn't contain the {0} event", eventName));

    // Prepare the TaskCompletionSource, the return variable and the right handler
    TaskCompletionSource<Targs> tcs = new TaskCompletionSource<Targs>();

    Delegate handler;

    if (eventInfo.EventHandlerType.Equals(typeof(EventHandler<Targs>)))
    {
        handler = new EventHandler<Targs>((sender, args) =>
        {
            tcs.SetResult(args);
        });
    }
    else
    {
        // PROBLEM: when this line is executed, the AddEventHandler method crashes
        handler = new TypedEventHandler<object, Targs>((sender, args) => 
       { 
           tcs.SetResult(args); 
       });
    }

    // Add the handler and wait for the event
    eventInfo.AddEventHandler(target, handler);
    CancellationTokenSource cts = new CancellationTokenSource(timeout);
    try
    {
        // If the event was triggered before the timout expired, return its args
        return await tcs.Task.GetWatchedTask(cts);
    }
    catch (OperationCanceledException)
    {
        // If the timout expired, just return null
        return null;
    }
    finally
    {
        // Remove the handler from the target object
        eventInfo.RemoveEventHandler(target, handler);
    }
}

现在,一切都适用于标准事件,所以这里没有问题。 当我有RoutedEvents时,我得到一个例外。 我最终尝试使用TypedEventHandler类,因为我没有找到另一种方法来获取这些事件的正确委托(如所有指针事件)。 但是当我尝试添加处理程序时,我得到了InvalidOperationException

是否可以在运行时为RoutedEvents创建处理程序,或者在WinRT上是不可能的?

感谢您的帮助!

塞尔吉奥

1 个答案:

答案 0 :(得分:2)

您得到该异常,因为WinRT不允许您使用AddHandler方法添加事件处理程序。我所知道的唯一方法就是使用以下代码:

    private void AddHandler(FrameworkElement element, object parameter, EventInfo eventInf)
    {
        var addMethod = eventInf.AddMethod;
        var removeMethod = eventInf.RemoveMethod;

        var addParameters = addMethod.GetParameters();
        var delegateType = addParameters[0].ParameterType;

        Action<object, object> handler = (s, e) => ExecuteCommand();
        var handlerInvoke = typeof(Action<object, object>).GetRuntimeMethod("Invoke", new[] { typeof(object), typeof(object) });

        var @delegate = handlerInvoke.CreateDelegate(delegateType, handler);

        Func<object, EventRegistrationToken> add = a => (EventRegistrationToken)addMethod.Invoke(element, new object[] { @delegate });
        Action<EventRegistrationToken> remove = t => removeMethod.Invoke(element, new object[] { t });

        WindowsRuntimeMarshal.AddEventHandler(add, remove, handler);
    }

要删除处理程序,请使用:

WindowsRuntimeMarshal.RemoveEventHandler(remove, handler);
相关问题