2012-06-21 45 views
1

我試圖創建一個RelayCommand與參數動態的實例:如何使用參數從lambda表達式創建委託?

public class RelayCommand<T> : ICommand 
{ 
    #region Declarations 

    private readonly Predicate<T> _canExecute; 
    private readonly Action<T> _execute; 

    #endregion 

    #region Constructors 

    /// <summary> 
    /// Initializes a new instance of the <see cref="RelayCommand&lt;T&gt;"/> class and the command can always be executed. 
    /// </summary> 
    /// <param name="execute">The execution logic.</param> 
    public RelayCommand(Action<T> execute) 
     : this(execute, null) 
    { 
    } 

    /// <summary> 
    /// Initializes a new instance of the <see cref="RelayCommand&lt;T&gt;"/> class. 
    /// </summary> 
    /// <param name="execute">The execution logic.</param> 
    /// <param name="canExecute">The execution status logic.</param> 
    public RelayCommand(Action<T> execute, Predicate<T> canExecute) 
    { 
     if (execute == null) 
      throw new ArgumentNullException("execute"); 
     _execute = execute; 
     _canExecute = canExecute; 
    } 

我有一個視圖模型有多種方法,現在我只是名單:

public void MyMethod(object parameter); 
public bool CanMyMethod(object parameter); 

我想動態掛鉤他們RelayCommand的實例如下:

ICommand command = new RelayCommand<ViewModel>((x)=>myviewmodel.MyMethod(myparameter),(x)=> myviewmodel.CanExecuteMyMethod(myparameter)); 

的前行的作品,然而,我的方法名稱在運行時通過這樣我需要實現同樣的事情,但動態。

編輯:只是一些澄清:在我的情況下,我不能直接引用我的方法。我將用來創建一個RelayCommand的方法名稱將被視爲STRING。

SOLUTION:

這裏是我的最終解決方案,使用@ZafarYousafi建議。注意我是如何用一個通用的「對象」型我RelayCommand和行動和謂語,因爲這是我的方法的參數類型(對象myparameter):這應該是等同於

object myparameter = //Some value gets assigned here. 
       Delegate td1 = null, td2 = null; 
       MethodInfo method1 = myviewmodel.GetType().GetMethod("MyMethodNameAsString"); 

       if (tmethod1 != null) 
        td1 = Delegate.CreateDelegate(typeof(Action<object>), myviewmodel, method1); 

       MethodInfo tmethod = viewmodel.GetType().GetMethod("Can" + "MyMethodNameAsString"); 
       if (method2 != null) 
        d2 = Delegate.CreateDelegate(typeof(Predicate<object>), myviewmodel, method2); 

       if (d1 != null && d2 != null) 
       { 
        item.Command = new RelayCommand<object>(obj => ((Action<object>) td1)(myparameter), obj => ((Predicate<object>)td2)(myparameter)); 
       } 

item.Command = new RelayCommand<object>(param=>myviewmodel.MyMethod(myparameter),param=>myviewmodel.CanMyMethod(myparameter)); 

重要提示:正如@DanC指出的那樣,由Josh Smith創建的RelayCommand類不打算在創建時接收參數。在架構良好的MVVM解決方案中,RelayCommand參數將通過CommandParameter屬性的XAML綁定傳遞。所以,如果你有一個綁定到一個RelayCommand你button.Command還需要綁定button.CommandParameter作爲解釋here: MVVM RelayCommand with parameters

OLD不成功的嘗試: 這是我到目前爲止有:

   Delegate d1 = null, d2 = null; 
       MethodInfo method1 = myviewmodel.GetType().GetMethod("MyMethodNameAsString"); 
       if (method1 != null) 
        d1 = Delegate.CreateDelegate(typeof(Action<ViewModel>), myviewmodel, method1); 

       MethodInfo method2 = myviewmodel.GetType().GetMethod("Can" + "MyMethodNameAsString"); 
       if (method2 != null) 
        d2 = Delegate.CreateDelegate(typeof(Predicate<ViewModel>), myviewmodel, method2); 

       if (d1 != null && d2 != null) 
       { 
        item.Command = new RelayCommand<ViewModel>((Action<ViewModel>)d1, (Predicate<ViewModel>)d2); 
       } 

這運行正常,沒有編譯或運行時錯誤,但我沒有找到如何 傳遞我的參數通過RelayComand構造函數參數。

任何意見將非常讚賞,

感謝

與我previous question

+0

是RelayCommand的方法或類的名字嗎?請發佈完整的代碼 – Bond

+0

它是一個類從Josh史密斯我相信,只是發佈它 –

+1

你已經鍵入代理投入行動,現在你有充分的自由傳遞參數((行動)d1)(yourparameter) – ZafarYousafi

回答

-2

u必須鍵入投委託採取行動,現在u有充分的自由來傳遞參數((Action<ViewModel>)d1)(yourparameter)

+0

這不適用於我,它說:'我的參數類型的參數'不能分配給參數類型ViewModel' –

+0

好吧,我得到它的工作。我的方法參數類型是'對象',所以我必須設置該類型的動作和謂詞 RelayCommand參數。我會將你的答案標記爲答案,因爲它指出我正確的解決方案。再次感謝@Zafar_Yousafi –

+0

我很高興我能夠幫助你。 – ZafarYousafi

-1

您RelayCommand類只要定義一個方法,像這樣執行命令:

public void Execute(T model) 
    { 
     if(_canExecute(model)) 
      _execute(model); 
    } 
+0

是啊,但這就是我在這裏試圖避免的情況。總的來說,我喜歡.NET,但我確實發現,它試圖迫使人們在真正不需要的情況下製作方法甚至是全新的方法。這些情況中的許多似乎涉及列舉比較。 – user1172763

1

根據Josh Smith在MVVM article中發佈的代碼。你會使用lambda變量參數來傳遞參數。在你的例子中,你根本沒有使用「x」lambda變量。這個變量應該是你的Execute和CanExecute方法的參數。

RelayCommand _saveCommand; 
public ICommand SaveCommand 
{ 
    get 
    { 
     if (_saveCommand == null) 
     { 
      _saveCommand = new RelayCommand(param => this.Save(), 
       param => this.CanSave); 
     } 
     return _saveCommand; 
    } 
} 

假設命令是在ViewModel中創建的,那麼你可以按如下方式初始化它。

ICommand command = new RelayCommand<MyParameterType>((myparameter)=>this.MyMethod(myparameter),(myparameter)=> this.CanExecuteMyMethod(myparameter)); 

由於您無法使用lamba來構造命令,您的代碼將如下所示。

Delegate d1 = null, d2 = null; 
      MethodInfo method1 = myviewmodel.GetType().GetMethod("MyMethodNameAsString"); 
      if (method1 != null) 
       d1 = Delegate.CreateDelegate(typeof(Action<YourParameterType>), myviewmodel, method1); 

      MethodInfo method2 = myviewmodel.GetType().GetMethod("Can" + "MyMethodNameAsString"); 
      if (method2 != null) 
       d2 = Delegate.CreateDelegate(typeof(Predicate<YourParameterType>), myviewmodel, method2); 

      if (d1 != null && d2 != null) 
      { 
       item.Command = new RelayCommand<YourParameterType>((Action<YourParameterType>)d1, (Predicate<YourParameterType>)d2); 
      } 

現在命令已分配給菜單項的對象,這是在這種情況下,ICommandSource後,它會調用您的兩名代表(D1,D2)與CommandParameter。

+0

瞭解,但同樣,我不能直接引用this.MyMethod,因爲方法名稱「MyMethod」將來自我的數據庫(作爲字符串),因此我無法對其引用進行硬編碼... –

+1

您可以顯示我的RelayCommand構造函數?如果它接受只是行動,謂詞那麼你可以替代對象的泛型類型,而不是你的ViewModel。然後當RelayCommand實際調用Execute和CanExecute時,它會將參數傳遞給Action 和Predicate 。 –

+1

對不起,只是注意到它確實接受這些參數類型。由於RelayCommand接受動作,謂詞當您構建命令時,不需要傳遞參數。當RelayCommand對象需要調用這些委託時,它應該將參數傳遞給它們。爲了這個工作正常,我想你想使用Object作爲泛型類型參數而不是ViewModel。 –

0

看來,其中構建RelayCommand例如在網站上,你已經得到了你需要通過從代表一切方法myviemodel的實例。

item.command = new RelayCommand<ViewModel>(
    myviemodel.MyMethod, myviewmodel.CanExecuteMyMethod) 

你所描述的情況是可能的Delegate.DynamicInvoke工作,但我不認爲有必要在你的片段......