如何在没有Reactive框架的情况下在WinRT中动态绑定事件到命令?

时间:2013-05-20 10:12:19

标签: windows-8 windows-runtime system.reactive

我正在为我的Windows 8应用according to this guide实施行为的修改版本。它的工作原理除了需要Reactive框架的地方外:

protected override void OnAttached()
{
  var evt = AssociatedObject.GetType().GetRuntimeEvent(Event);
  if (evt != null)
  {
    Observable.FromEventPattern<RoutedEventArgs>(AssociatedObject, Event)
      .Subscribe(se => FireCommand());
  }
  base.OnAttached();
}

问题很简单,如何在没有Reactive frmaework的情况下实现类似的功能?我浏览了可以obtained here的Rx的来源,但我对我来说太复杂了。
我还成功移植到代码,唯一的问题是它只适用于固定类型的EventHandler:

protected override void OnAttached()
{
    EventInfo evt = AssociatedObject.GetType().GetRuntimeEvent(Event);
    if (evt != null)
    {
        AssignEvent<ItemClickEventHandler>(AssociatedObject, Event, FireCommand);
    }
    base.OnAttached();
}

protected void AssignEvent<T1>(object instance, string eventName, T1 handler)
{
    EventInfo runtimeEvent = instance.GetType().GetRuntimeEvent(eventName);
    Func<T1, EventRegistrationToken> add = a => (EventRegistrationToken)runtimeEvent.AddMethod.Invoke(instance, new object[] { a });
    Action<EventRegistrationToken> remove = a => runtimeEvent.RemoveMethod.Invoke(runtimeEvent, new object[] { a });

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

任何想法,如何让它动态,所以我不必使用特定的事件处理程序“ItemClickEventHandler”?在经典.NET中注意它非常简单,但在WinRT中我不能使用 Delegate.CreateDelegate(...)

更新: 感谢 Brandon 我能够完成该方法,现在看起来像这样:

protected override void OnAttached()
{
    EventInfo evt = AssociatedObject.GetType().GetRuntimeEvent(Event);
    if (evt != null)
    {
        MethodInfo addMethod = evt.AddMethod;
        MethodInfo removeMethod = evt.RemoveMethod;
        ParameterInfo[] addParameters = addMethod.GetParameters();
        Type delegateType = addParameters[0].ParameterType;
        Action<object, object> handler = (s, e) => FireCommand(e as RoutedEventArgs);
        MethodInfo handlerInvoke = typeof(Action<object, object>).GetRuntimeMethod("Invoke", new[] { typeof(object), typeof(object) });
        Delegate @delegate = handlerInvoke.CreateDelegate(delegateType, handler);

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

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

现在我可以移除800kB的Rx dll,再次感谢!

1 个答案:

答案 0 :(得分:2)

我浏览了Rx源代码,这是重要的功能:

MethodInfo addMethod = eventInfo.GetAddMethod();
MethodInfo removeMethod = eventInfo.GetRemoveMethod();
var addParameters = addMethod.GetParameters();
var delegateType = addParameters[0].ParameterType;
Action<object, object> handler = (object sender, object eventArgs) => FireCommand();
MethodInfo handlerInvoke = typeof(Action<object, object>).GetMethod("Invoke");
Delegate delegate = handlerInvoke.CreateDelegate(delegateType, handler);

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

看起来重要的信息是他们正在使用MethodInfo.CreateDelegate