【问题标题】:Dynamic Event Subscription and 1 handler动态事件订阅和 1 个处理程序
【发布时间】:2013-03-16 00:56:37
【问题描述】:

我已经看到了几个答案,但不知何故我无法让我的工作。我想动态使用各种控件(文本框、复选框、按钮等)的任何事件,最好将它们分配给一个事件处理程序。应在运行时分配处理程序。此外,我想在处理程序中知道哪个事件触发了处理程序。

我让它部分工作。使用 lambda 表达式,我调用我的处理程序(EventAssistant)并传递一个包含事件名称的额外参数(命令)。它适用于使用 EventHandler 类型的事件。但是,它不适用于需要不同处理程序的事件,例如 MouseEventHandler 类型。它将无法在 AddEventHandler 处订阅。

private void RegisterEventHandlers(Control ctl)
{
  foreach (Command command in CommandList)
  {
    EventInfo eventInfo = ctl.GetType().GetEvent(command.Name);
    EventHandler handler = (sender, args) =>
    {
      EventAssistant(sender, args, command);
    };
    eventInfo.AddEventHandler(ctl, handler);
  }
}

public void EventAssistant(object sender, EventArgs e, Command c)
{
  //do lots of other fun stuff
}

基于C# passing extra parameters to an event handler?


作为替代方案,我尝试使用表达式树来解决问题,如下所示:Why am I getting an Argument exception when creating event handler dynamically? 显然,可以从 EventInfo 中检索 EventHandlerType 并在 lambda 表达式中使用。

但是,无论我做什么,我总是得到一个 InvalidOperationException “Lambda Parameter not in scope”。

private void RegisterEventHandlers(Control ctl)
{
  foreach (Command command in CommandList)
  {
    EventInfo eventInfo = ctl.GetType().GetEvent(command.Name);

    var sender = Expression.Parameter(typeof(object), "sender");
    var e = Expression.Parameter(typeof(EventArgs), "e");
    var c = Expression.Parameter(typeof(Command), "command");
    Expression[] arg = new Expression[] { sender, e, c };
    MethodInfo mi = this.GetType().GetMethod("EventAssistant");
    var body = Expression.Call(Expression.Constant(this), mi, arg);
    var lambda = Expression.Lambda(eventInfo.EventHandlerType, body, sender, e);

    eventInfo.AddEventHandler(ctl, lambda.Compile());
  }
}

我在表达式树上做错了什么?

另外,第一段代码看起来更干净。是否可以使用第一个代码示例得到我想要的?

【问题讨论】:

标签: c# events reflection


【解决方案1】:

在您的第二次尝试中,变量c 不应该是ParameterExpression,而是一个ConstantExpression,其值设置为当前command。使用当前代码,您正在创建一个处理程序,它基本上如下所示:

(_sender, _e) => this.EventAssistant(_sender, _e, _c)
// The expression expects "_c" to be a parameter of the lambda, which is why
// you're getting that exception

但是,如果你改变了

var c = Expression.Parameter(typeof(Command), "command");

var c = Expression.Constant(command);

生成的代码看起来(当然也可以工作)如预期:

(_sender, _e) => this.EventAssistant(_sender, _e, command)

【讨论】:

  • 成功了!当然,EventAssistant 还不够通用,无法接受所有类型的事件处理程序,但我会将其留作后续问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-04
  • 2012-06-15
  • 2021-03-29
  • 1970-01-01
相关资源
最近更新 更多