C# 使用反射添加事件处理程序

C# 使用反射添加事件处理程序,c#,.net,wpf,events,reflection,C#,.net,Wpf,Events,Reflection,我有一个带有所谓命令的.json文件: "Commands":[{ "EventName": "MouseLeftButtonUp", "MethodToExecute": "NextJson", "Args": "Next.json" },{ "EventName": "MouseRightButtonUp", "MethodToExecute": "CloseApp" } 我将此json反序列化到此类: 公共类命令 { [JsonPropertyName(“E

我有一个带有所谓命令的
.json
文件:

"Commands":[{
   "EventName": "MouseLeftButtonUp",
   "MethodToExecute": "NextJson",
   "Args": "Next.json"
},{
   "EventName": "MouseRightButtonUp",
   "MethodToExecute": "CloseApp"
}
我将此json反序列化到此类:

公共类命令
{
[JsonPropertyName(“EventName”)]
公共字符串EventName{get;set;}
[JsonPropertyName(“MethodToExecute”)]
公共字符串方法执行{get;set;}
[JsonPropertyName(“Args”)]
公共字符串Args{get;set;}
/*方法*/
}
EventName
UIElement
类事件的名称。
MethodToExecute
是事件触发时要调用的方法的名称。
Args
是传递给
MethodToExecute
的Args

我不希望我的用户能够调用应用程序中的任何方法,因此我不使用反射来获取
MethodInfo
,而是创建
Dictionary
Dictionary methods Dictionary
。本词典中的
键是方法的名称(
MethodToExecute
from
Command
class),其值如下:

MethodsDictionary.Add(名称(CloseApp)、新操作(CloseApp));
Add(nameof(NextJson),newaction(NextJson));
在不使用反射的情况下,我添加了如下事件处理程序:

button.MouseLeftButtonUp+=(发送方,args)=>MethodsDictionary[command.MethodToExecute].DynamicInvoke(command.args);
但我想对事件进行动态绑定。当然,我可以在
command.Name
属性上通过难看的
开关盒
,但我仍然想尝试反射解决方案。 在我看来,解决方案应该是这样的:

foreach(命令中的var命令)
{
Bind(uielement,MethodsDictionary[command.MethodToExecute]);
}
//和command.Bind方法类似:
公共void绑定(UIElement UIElement,委托方法执行)
{
//我知道没有像GetEventHandler这样的方法,只是一个例子
var handler=uielement.GetEventHandler(EventName);
handler+=(发送方,args)=>methodToExecute.DynamicInvoke(args);
}
我搜索了几个非常相似的问题:

但这些并不能帮助我以我想要的方式解决问题。我尝试了上面的一些解决方案,但都不适合我,除了不同的例外,都失败了

UPD

如上所述,我试图通过
开关大小写
实现处理程序绑定。它在
命令
类中产生了此方法:

公共void绑定(UIElement)
{
开关(此.Name)
{
案例“MouseRightButtonUp”:
{
element.MouseRightButtonUp+=(发件人,args)=>MethodsDictionary[this.MethodToExecute].DynamicInvoke(this.args);
打破
}
案例“点击”:
{
//UIElement没有单击事件
var button=作为ButtonBase的元素;
按钮。单击+=(发件人,参数)=>MethodsDictionary[this.MethodToExecute].DynamicInvoke(this.args);
打破
}
/*等等*/
违约:
{
抛出新的NotSupportedException();
}
}
}

我不喜欢,添加新处理程序的部分只是上一节的复制粘贴,但在这种情况下,我看不到其他解决方法。我想在这种情况下使用反射,但我不知道这是否可行。

如果反射无法正常工作,可以使用另一个
字典
来存储支持的事件订阅方方法:

Command.cs

public class Command
{
    [JsonPropertyName("EventName")]
    public string EventName { get; set; }

    [JsonPropertyName("MethodToExecute")]
    public string MethodToExecute { get; set; }

    [JsonPropertyName("Args")]
    public string Args { get; set; }

    /*Methods*/
}
class JsonEventMapper
{
  private Dictionary<string, Action<UIElement, EventHandler>>> SupportedEventSubscriberMap { get; }
  private Dictionary<string, EventHandler> RegisteredEventHandlerMap { get; }   

  public JsonEventMapper()
  {
    this.SupportedEventSubscriberMap = new Dictionary<string, Action<UIElement, EventHandler>>() 
    { 
      { 
        nameof(UIElement.MouseRightButtonUp), (uiElement, handler) => uiElement.MouseRightButtonUp += handler.Invoke 
      },
      { 
        nameof(UIElement.LostFocus), (uiElement, eventSubscriber) => uiElement.LostFocus += handler.Invoke 
      }
    };

    this.RegisteredEventHandlerMap = new Dictionary<string, EventHandler>()
    {
      {
        nameof(UIElement.MouseLeftButtonUp), CloseApp
      },
      {
        nameof(UIElement.LostFocus), NextJson
      }
    };
  }

  public void RegisterJsonCommands(IEnumerable<Command> commands, UIElement uiElement)
  {    
    foreach (var command in commands)
    {
      BindCommandToEvent(uiElement, command);
    }
  }

  private void BindCommandToEvent(UIElement uiElement, Command command)
  {    
    if (this.SupportedEventSubscriberMap.TryGetValue(command.EventName, out Action<UIElement, EventHandler> eventSubscriber)
      && this.RegisteredEventHandlerMap.TryGetValue(command.EventName, out EventHandler eventHandler))
    {
      eventSubscriber.Invoke(uiElement, eventHandler);
    }
  }

  private void CloseApp(object sender, EventArgs args)
  {    
    // Handle event
  }

  private void NextJson(object sender, EventArgs args)
  {    
    // Handle event
  }
}
JsonEventMapper.cs

public class Command
{
    [JsonPropertyName("EventName")]
    public string EventName { get; set; }

    [JsonPropertyName("MethodToExecute")]
    public string MethodToExecute { get; set; }

    [JsonPropertyName("Args")]
    public string Args { get; set; }

    /*Methods*/
}
class JsonEventMapper
{
  private Dictionary<string, Action<UIElement, EventHandler>>> SupportedEventSubscriberMap { get; }
  private Dictionary<string, EventHandler> RegisteredEventHandlerMap { get; }   

  public JsonEventMapper()
  {
    this.SupportedEventSubscriberMap = new Dictionary<string, Action<UIElement, EventHandler>>() 
    { 
      { 
        nameof(UIElement.MouseRightButtonUp), (uiElement, handler) => uiElement.MouseRightButtonUp += handler.Invoke 
      },
      { 
        nameof(UIElement.LostFocus), (uiElement, eventSubscriber) => uiElement.LostFocus += handler.Invoke 
      }
    };

    this.RegisteredEventHandlerMap = new Dictionary<string, EventHandler>()
    {
      {
        nameof(UIElement.MouseLeftButtonUp), CloseApp
      },
      {
        nameof(UIElement.LostFocus), NextJson
      }
    };
  }

  public void RegisterJsonCommands(IEnumerable<Command> commands, UIElement uiElement)
  {    
    foreach (var command in commands)
    {
      BindCommandToEvent(uiElement, command);
    }
  }

  private void BindCommandToEvent(UIElement uiElement, Command command)
  {    
    if (this.SupportedEventSubscriberMap.TryGetValue(command.EventName, out Action<UIElement, EventHandler> eventSubscriber)
      && this.RegisteredEventHandlerMap.TryGetValue(command.EventName, out EventHandler eventHandler))
    {
      eventSubscriber.Invoke(uiElement, eventHandler);
    }
  }

  private void CloseApp(object sender, EventArgs args)
  {    
    // Handle event
  }

  private void NextJson(object sender, EventArgs args)
  {    
    // Handle event
  }
}
JsonEventMapper类
{
私有字典>支持的EventSubscriberMap{get;}
专用字典注册表deventhandlermap{get;}
公共JsonEventMapper()
{
this.SupportedEventSubscriberMap=新字典()
{ 
{ 
nameof(UIElement.MouseRightButtonUp),(UIElement,handler)=>UIElement.MouseRightButtonUp+=handler.Invoke
},
{ 
nameof(UIElement.LostFocus),(UIElement,eventSubscriber)=>UIElement.LostFocus+=handler.Invoke
}
};
this.RegisteredEventHandlerMap=新字典()
{
{
CloseApp的名称(UIElement.mouseleftbuttonnup)
},
{
nameof(UIElement.LostFocus),NextJson
}
};
}
公共无效注册表JsonCommand(IEnumerable命令,UIElement UIElement)
{    
foreach(命令中的var命令)
{
BindCommandToEvent(uiElement,command);
}
}
私有void BindCommandToEvent(UIElement UIElement,Command)
{    
if(this.SupportedEventSubscriberMap.TryGetValue(command.EventName,out Action eventSubscriber)
&&this.RegisteredEventHandlerMap.TryGetValue(command.EventName,out EventHandler EventHandler))
{
Invoke(uiElement,eventHandler);
}
}
私有void CloseApp(对象发送方、事件args args)
{    
//处理事件
}
私有void NextJson(对象发送方、事件args args)
{    
//处理事件
}
}
用法
IEnumerable commands=反序列化JSONTOCommands();
var eventMapper=new JsonEventMapper();
RegisterJsonCommands(命令、按钮);
您肯定想根据您的特定场景调整细节


不要忘记取消订阅活动(例如,通过定义另一个
supportedEventSubscriberMap
)。

我认为您尝试的是这样的:

public class CommandModel
{
    /// properties

    public void Bind(UIElement element)
    {
        EventBinder.Bind(() => MainViewModel.RunCommand(MethodToExecute, Args), element, EventName);
    }
}

public static class EventBinder
{
    public static void Bind(Action action, object eventSource, string eventName)
    {
        var eventInfo = eventSource.GetType().GetEvent(eventName);

        EventHandler eventHandler = (s, e) => action();

        eventInfo.AddEventHandler(eventSource, ConvertDelegate(eventHandler, eventInfo.EventHandlerType));
    }

    private static Delegate ConvertDelegate(Delegate originalDelegate, Type targetDelegateType)
    {
        return Delegate.CreateDelegate(
            targetDelegateType,
            originalDelegate.Target,
            originalDelegate.Method);
    }
}

谢谢你详细的回答!正如我在OP中提到的,我试图通过
开关案例
实现处理程序绑定。它在
命令
类(更新的OP)中产生了这个方法
Bind
。我不喜欢,添加新处理程序的部分只是上一节的复制粘贴,但在这种情况下,我看不到其他解决方法。我还没有尝试你的解决方案,但是