如何在运行时通过动态反射创建RelayCommand实例? [英] How to create instance of RelayCommand at runtime through dynamic reflection?

查看:72
本文介绍了如何在运行时通过动态反射创建RelayCommand实例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在WPF中构建MVVM应用程序,并将菜单绑定到MenuItem模型。我的MenuItem类具有以下属性:

I'm building an MVVM application in WPF and I am binding a Menu to a MenuItem model. My MenuItem class has these properties :

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模型类由来自数据库的数据填充。在这种
情况下,从DB填充的唯一属性是CommandName。

This MenuItem model class is populated from Data coming from a database. In this case, the only property populated from DB is CommandName.

假设它用字符串 OpenFile填充

Let's say it populates it with the string "OpenFile"

编辑
这是我的MenuViewModelConstructor:

EDIT Here my MenuViewModelConstructor:

    public MenuViewModel(MainViewModel _MainViewModel)
    {
       ....
    }

它与MainViewModel有依赖关系,因为这是OpenFile和CanOpenFile方法的所在。

It has a dependency to MainViewModel because that's where the OpenFile and CanOpenFile methods live.

我的MenuViewModel有一种注册命令的方法,如下所示:

My MenuViewModel has a method to register Commands as follows:

        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);
            }
        }

顺便说一下,R​​elayCommand的签名是:

By the way, the signature of RelayCommand is:

public RelayCommand(Action execute, Func<bool> canExecute)

是可以使用反射或动态lambda或类似的方法实例化我的RelayCommand,以便我可以在运行时动态地使用来自数据库的Command字符串?什么是最佳方式?

Is it possible to instantiate my RelayCommand with Reflection or dynamic lambdas or something like that so I can use my Command string coming from the database at runtime dynamically? What would be the most optimal way?

编辑:解决方案
感谢@Nathan为我指出了正确的解决方案,这是我的工作方法:

SOLUTION Thanks to @Nathan for pointing me to the right solution, here is my working method:

    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

I am using .NET 4.0

谢谢!

推荐答案

我用搜索创建了一个具有反射的代表的Google快速搜索并找到了这篇相当不错的文章如何:使用反射挂钩代表

I did a quick google search on creating delegates with reflection and found this pretty good article How to: Hook Up a Delegate Using Reflection

我在本地计算机上创建了一个快速测试并使其正常工作

I created a quick test on my local machine and got it to work

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)工作的视图

where this in CreateDelegate is the view I was working from (MainWindow)

您必须对其进行一些微调才能使之工作,但我想象它会是这样的:

You'll have to tweak it a bit to get your's to work but I imagine it would be something like:

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

这篇关于如何在运行时通过动态反射创建RelayCommand实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆