【发布时间】:2020-03-02 18:40:34
【问题描述】:
我有一个带有所谓命令的.json 文件:
"Commands":[{
"EventName": "MouseLeftButtonUp",
"MethodToExecute": "NextJson",
"Args": "Next.json"
},{
"EventName": "MouseRightButtonUp",
"MethodToExecute": "CloseApp"
}
我将这个 json 反序列化为这个类:
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*/
}
EventName 是UIElement 类事件的名称。
MethodToExecute 是事件触发时调用的方法名称。
Args 是参数,传递给MethodToExecute。
我不希望我的用户能够调用应用程序中的任何方法,所以我不使用反射来获取MethodInfo,而是创建Dictionary:Dictionary<string, Delegate> MethodsDictionary。这个字典中的key是方法的名称(MethodToExecute来自Command类),值是这样的:
MethodsDictionary.Add(nameof(CloseApp), new Action(CloseApp));
MethodsDictionary.Add(nameof(NextJson), new Action<string>(NextJson));
没有使用反射,我添加了这样的事件处理程序:
button.MouseLeftButtonUp += (sender, args) => MethodsDictionary[command.MethodToExecute].DynamicInvoke(command.Args);
但我想对事件进行动态绑定。好吧,我当然可以在command.Name 属性上通过丑陋的switch-case,但我仍然想尝试使用反射的解决方案。
在我看来,解决方案应该类似于:
foreach (var command in commands)
{
command.Bind(uielement, MethodsDictionary[command.MethodToExecute]);
}
//And command.Bind method is like:
public void Bind(UIElement uielement, Delegate methodToExecute)
{
//I know there's no such method like GetEventHandler, just an example
var handler = uielement.GetEventHandler(EventName);
handler += (sender, args) => methodToExecute.DynamicInvoke(Args);
}
我搜索了几个非常相似的问题:
Subscribe to an event with Reflection
AddEventHandler using reflection
Add Event Handler using Reflection ? / Get object of type?
但是这些并不能帮助我以我想要的方式解决问题。我尝试了上面的一些解决方案,但它们对我不起作用,失败并出现不同的异常。
更新。
如上所述,我尝试通过switch-case 实现处理程序绑定。它导致了Command类中的这个方法:
public void Bind(UIElement element)
{
switch (this.Name)
{
case "MouseRightButtonUp":
{
element.MouseRightButtonUp += (sender, args) => MethodsDictionary[this.MethodToExecute].DynamicInvoke(this.Args);
break;
}
case "Click":
{
//UIElement doesn't have Click event
var button = element as ButtonBase;
button.Click += (sender, args) => MethodsDictionary[this.MethodToExecute].DynamicInvoke(this.Args);
break;
}
/*And so on for each event*/
default:
{
throw new NotSupportedException();
}
}
}
我不喜欢,添加新处理程序的那部分只是上一节的复制粘贴,但在这种情况下我看不到另一种解决方法。我想在这种情况下使用反射,但我不知道是否可以。
【问题讨论】:
标签: c# .net wpf events reflection