Как создать экземпляр RelayCommand во время выполнения посредством динамического отражения?
Я создаю приложение MVVM в WPF и привязываю Menu к модели MenuItem. Мой класс MenuItem имеет следующие свойства:
public class MenuItem
{
private List<MenuItem> _Items;
public MenuItem(string header, ICommand command)
{
Header = header;
Command = command;
}
public MenuItem()
{
}
public string Header { get; set; }
public List<MenuItem> Items
{
get { return _Items ?? (_Items = new List<MenuItem>()); }
set { _Items = value; }
}
public ICommand Command { get; set; }
public string CommandName { get; set; }
public object Icon { get; set; }
public bool IsCheckable { get; set; }
public bool IsChecked { get; set; }
public bool Visible { get; set; }
public bool IsSeparator { get; set; }
public string ToolTip { get; set; }
public int MenuHierarchyID { get; set; }
public int ParentMenuHierarchyID { get; set; }
public string IconPath { get; set; }
}
Этот класс модели MenuItem заполняется данными, поступающими из базы данных. В этом случае единственным свойством, заполненным из БД, является CommandName.
Допустим, он заполняет его строкой "OpenFile"
РЕДАКТИРОВАТЬ Вот мой MenuViewModelConstructor:
public MenuViewModel(MainViewModel _MainViewModel)
{
....
}
У него есть зависимость от MainViewModel, потому что там живут методы OpenFile и CanOpenFile.
Мой MenuViewModel имеет метод для регистрации команд следующим образом:
private void RegisterMenuCommand(MenuItem item)
{
if(!string.IsNullOrEmpty(item.CommandName))
{
//How can I create a new RelayCommand instance from
//my CommandName string????
//e.g. item.Command = new RelayCommand(_MainViewModel.<item.CommandNameHere>, _MainViewModel."Can" + <item.CommandNameHere>
item.Command = new RelayCommand(_MainViewModel.OpenFile, _MainViewModel.CanOpenFile);
}
foreach(MenuItem child in item.Items)
{
RegisterMenuCommand(child);
}
}
Кстати, подпись RelayCommand:
public RelayCommand(Action execute, Func<bool> canExecute)
Можно ли создать экземпляр RelayCommand с помощью Reflection или динамической лямбды или чего-то в этом роде, чтобы я мог динамически использовать мою командную строку, поступающую из базы данных? Что было бы наиболее оптимальным способом?
РЕДАКТИРОВАТЬ: РЕШЕНИЕ Спасибо @Nathan за указание на правильное решение, вот мой метод работы:
private void RegisterMenuCommand(MenuItem item)
{
if(!string.IsNullOrEmpty(item.CommandName))
{
MethodInfo method1 = _MainViewModel.GetType().GetMethod(item.CommandName);
Delegate d1 = Delegate.CreateDelegate(typeof(Action),_MainViewModel, method1);
MethodInfo method2 = _MainViewModel.GetType().GetMethod("Can" + item.CommandName);
Delegate d2 = Delegate.CreateDelegate(typeof (Func<bool>),_MainViewModel, method2);
item.Command = new RelayCommand((Action)d1, (Func<bool>)d2);
}
foreach(MenuItem child in item.Items)
{
RegisterMenuCommand(child);
}
}
Я использую.NET 4.0
Спасибо!
1 ответ
Я сделал быстрый поиск в Google по созданию делегатов с отражением и нашел эту довольно хорошую статью. Как: подключить делегата с помощью отражения
Я создал быстрый тест на моей локальной машине и заставил его работать
MethodInfo miHandler = typeof(MainWindow).GetMethod("OpenCommandHandler", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
Delegate d = Delegate.CreateDelegate(typeof(Action<object>), this, miHandler);
btnTest.Command = new DelegateCommand((Action<object>)d);
где this
в CreateDelegate
это вид, из которого я работал (MainWindow)
Вам придется немного настроить его, чтобы заставить его работать, но я думаю, что это будет что-то вроде:
var obj = <object containing your method>
MethodInfo miHandler = typeof(obj).GetMethod(item.CommandName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
Delegate openDelegate = Delegate.CreateDelegate(typeof(Action), obj, miHandler);
item.Command = new RelayCommand((Action)openDelegate, ...);