2012-06-20 3 views
1

Я создаю приложение MVVM в WPF, и я привязываю меню к модели MenuItem. Мой класс MenuItem имеет следующие свойства:Как создать экземпляр RelayCommand во время выполнения через динамическое отражение?

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»

EDIT Вот мой 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 с отражением или динамическим lambdas или что-то в этом роде, поэтому я могу использовать мою строку Command, идущую из базы данных во время выполнения динамически? Что было бы самым оптимальным способом?

EDIT: РЕШЕНИЕ Благодаря @ Натан указал мне на правильное решение, вот мой метод работы:

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

Спасибо!

+0

Почему ваш MenuViewModel имеет ссылку на ваш MainViewModel? (как показано в вашем самом большом блоке кода) – EkoostikMartin

+0

О, потому что реализация метода OpenFile и CanOpenFile живут в MainViewModel –

+0

Так почему бы не создать свойства для хранения ссылок на методы OpenFile и CanOpenFile в вашем классе MenuItem? Затем вы можете передать эту ссылку на конструктор RelayCommand()? – EkoostikMartin

ответ

1

Я сделал быстрый поиск Google по созданию делегатов с отражением и нашел очень хорошую статью How to: Hook Up a Delegate Using Reflection

я создал быстрый тест на моей локальной машине и получил его на работу

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, ...); 
+0

бинго! вот и все, спасибо огромное @ Натан! –

Смежные вопросы