【问题标题】:How to create instance of RelayCommand at runtime through dynamic reflection?如何通过动态反射在运行时创建 RelayCommand 的实例?
【发布时间】:2012-06-23 01:13:51
【问题描述】:

我正在 WPF 中构建一个 MVVM 应用程序,并将一个 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 模型类由来自数据库的数据填充。在这 在这种情况下,从 DB 填充的唯一属性是 CommandName。

假设它用字符串“OpenFile”填充它

编辑 这是我的 MenuViewModelConstructor:

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

它依赖于 MainViewModel,因为这是 OpenFile 和 CanOpenFile 方法所在的地方。

我的 MenuViewModel 有一个注册 Commands 的方法如下:

        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 的签名是:

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

是否可以使用反射或动态 lambda 或类似的东西来实例化我的 RelayCommand,以便我可以在运行时动态使用来自数据库的命令字符串?什么是最理想的方式?

编辑:解决方案 感谢@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

谢谢!

【问题讨论】:

  • 为什么你的 MenuViewModel 引用了你的 MainViewModel? (如你最大的代码块所示)
  • 哦,因为 OpenFile 方法实现和 CanOpenFile 存在于 MainViewModel 中
  • 那么为什么不在 MenuItem 类中创建属性来保存对“OpenFile”和“CanOpenFile”方法的引用呢?然后你可以将该引用传递给 RelayCommand() 构造函数?
  • 不确定你的意思@EkoostikMartin。在我知道方法的名称之前,我无法创建引用,该名称在运行时来自 DB..
  • 能否请您包含您的 MenuItem 类的整个主体?还有填充属性的代码?

标签: c# reflection dynamic mvvm runtime


【解决方案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);

CreateDelegate 中的 this 是我正在使用的视图(主窗口)

你必须稍微调整一下才能让你的工作正常,但我想它会是这样的:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-23
    • 2011-10-15
    • 2012-02-25
    • 1970-01-01
    • 1970-01-01
    • 2011-07-05
    • 2013-05-11
    相关资源
    最近更新 更多