我正在研究一种扩展方法,但我在使用其中的一部分时遇到了一些问题。
想法是这样的:我想创建一个方法,它接受一个对象和一个事件的名称,等待事件被引发,然后返回它的事件参数。 我会使用它来避免每次在我的代码中执行此类操作时都必须手动创建委托(delegate)和其他内容。
注意:该代码位于针对 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
类,因为我没有找到另一种方法来为这些事件(如所有指针事件)获取正确的委托(delegate)。
但是当我尝试添加处理程序时,我得到一个 InvalidOperationException
。
是否也可以在运行时为 RoutedEvents 创建处理程序,或者这在 WinRT 上是不可能的?
感谢您的帮助!
塞尔吉奥
最佳答案
您会收到该异常,因为 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);
关于c# - 如何以编程方式将 TypedEventHandler 添加到 RoutedEvents?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31273109/