简体   繁体   English

动态事件订阅和1个处理程序

[英]Dynamic Event Subscription and 1 handler

I have seen several answers already but somehow I can't get mine to work. 我已经看到了几个答案,但不知怎的,我不能让我的工作。 I want to dynamically use any of the events of various controls (textbox, checkbox, button, etc) and, preferably, assign them to one event handler. 我想动态使用各种控件的任何事件(文本框,复选框,按钮等),最好将它们分配给一个事件处理程序。 The handler should be assigned at runtime. 应在运行时分配处理程序。 Furthermore, I want to know in the handler which event triggered the handler. 此外,我想在处理程序中知道哪个事件触发了处理程序。

I got this to work partially. 我得到了部分工作。 Using a lambda expression I call my handler (EventAssistant) and pass an extra parameter (command) which contains the name of the event. 使用lambda表达式我调用我的处理程序(EventAssistant)并传递一个包含事件名称的额外参数(命令)。 It works for events that use type EventHandler. 它适用于使用EventHandler类型的事件。 However, it won't work for events that expect a different handler such as type MouseEventHandler. 但是,它不适用于期望不同处理程序的事件,例如类型MouseEventHandler。 It will fail to subscribe at AddEventHandler. 它将无法在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
}

Based on C# passing extra parameters to an event handler? 基于C#将额外参数传递给事件处理程序?


As an alternative I tried to solve the problem with an Expression Tree as shown here: Why am I getting an Argument exception when creating event handler dynamically? 作为替代方案,我尝试使用表达式树来解决问题,如下所示: 为什么在动态创建事件处理程序时会出现Argument异常? Apparently, the EventHandlerType can be retrieved from the EventInfo and used in a lambda expression. 显然,可以从EventInfo中检索EventHandlerType并在lambda表达式中使用它。

But, whatever I do I always get an InvalidOperationException "Lambda Parameter not in scope". 但是,无论我做什么,我总是得到一个InvalidOperationException“Lambda参数不在范围内”。

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());
  }
}

What am I doing wrong with the Expression Tree? 我在表达树上做错了什么?

Also, the first piece of code looks a lot more clean. 此外,第一段代码看起来更干净。 Is it possible to get what I want using the first code sample? 是否有可能使用第一个代码示例得到我想要的东西?

In your second attempt, the variable c shouldn't be a ParameterExpression , but a ConstantExpression with the value set to the current command instead. 在第二次尝试中,变量c不应该是ParameterExpression ,而是ConstantExpression ,其值设置为当前command With the current code, you are creating a handler, which essentially looks like this: 使用当前代码,您将创建一个处理程序,它基本上如下所示:

(_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

However, if you change 但是,如果你改变了

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

to

var c = Expression.Constant(command);

the generated code will look (and work, of course) as expected: 生成的代码将按预期显示(并且当然可以工作):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM