1

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)
    {
       ....
    }

OpenFile および CanOpenFile メソッドが存在する場所であるため、MainViewModel に依存しています。

私の 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 をリフレクションまたは動的ラムダなどでインスタンス化して、実行時にデータベースから取得したコマンド文字列を動的に使用できるようにすることは可能ですか? 最も最適な方法は何でしょうか?

編集: 解決策正しい解決策を教えてくれた@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 を使用しています

ありがとう!

4

1 に答える 1

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

私が作業していたビューはどこthisCreateDelegateありますか (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, ...);
于 2012-06-20T20:44:16.880 に答える