У меня есть файл .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);
Но я бы хотел сделать динамическую c привязку событий. Ну, конечно, я могу сделать это через некрасивое свойство switch-case
на command.Name
, но я все же хотел бы попробовать решение с отражением. На мой взгляд, решение должно выглядеть примерно так:
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);
}
Я искал несколько довольно похожих вопросов:
Подписаться на событие с отражением
https://social.msdn.microsoft.com/Forums/vstudio/en-US/d7f184f1-0964-412a-8659-6759a0e2db83/c-reflection-problem-subscribing-to-event?forum=netfxbcl
https://docs.microsoft.com/en-us/dotnet/framework/reflection-and-codedom/how-to-hook-up-a-delegate-using-reflection
AddEventHandler с использованием отражения
Добавить обработчик событий используя Reflection? / Получить объект типа?
Но это не помогает мне решить проблему так, как я хочу. Я попробовал некоторые из приведенных выше решений, но у меня они не сработали, но с разными исключениями.
UPD.
Я пытался реализовать привязку обработчика через switch-case
, так как я упомянутый выше. Это привело к тому, что этот метод внутри Command
class:
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();
}
}
}
Мне не нравится, что эта часть с добавлением новых обработчиков является просто копией вставки предыдущего раздела, но я не вижу другого Обходной путь в этой ситуации. Я хотел бы использовать отражение в этом случае, но я не знаю, возможно ли это.