2012-08-14 58 views
14

將命令抽象到視圖模型中是XAML/MVVM項目的一個有價值的實踐。我明白了。而且,我在WinRT中看到了ICommand;但是,我們如何實現它?我還沒有找到真正有效的樣本。有人知道嗎?任何WinRT的iCommand/CommandBinding實現樣本在那裏?

+0

你應該接受一個答案 – 2012-08-20 18:25:56

+10

你應該有一定的耐心! – 2012-08-22 02:00:31

回答

19

我一直的最愛必須是由PnP團隊提供的DelegateCommand。它允許你創建一個類型的命令:

MyCommand = new DelegateCommand<MyEntity>(OnExecute); 
... 
private void OnExecute(MyEntity entity) 
{...} 

它還可以提供一種方式來提高CanExecuteChanged事件(禁用/啓用命令)

MyCommand.RaiseCanExecuteChanged(); 

下面的代碼:

public class DelegateCommand<T> : ICommand 
{ 
    private readonly Func<T, bool> _canExecuteMethod; 
    private readonly Action<T> _executeMethod; 

    #region Constructors 

    public DelegateCommand(Action<T> executeMethod) 
     : this(executeMethod, null) 
    { 
    } 

    public DelegateCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod) 
    { 
     _executeMethod = executeMethod; 
     _canExecuteMethod = canExecuteMethod; 
    } 

    #endregion Constructors 

    #region ICommand Members 

    public event EventHandler CanExecuteChanged; 

    bool ICommand.CanExecute(object parameter) 
    { 
     try 
     { 
      return CanExecute((T)parameter); 
     } 
     catch { return false; } 
    } 

    void ICommand.Execute(object parameter) 
    { 
     Execute((T)parameter); 
    } 

    #endregion ICommand Members 

    #region Public Methods 

    public bool CanExecute(T parameter) 
    { 
     return ((_canExecuteMethod == null) || _canExecuteMethod(parameter)); 
    } 

    public void Execute(T parameter) 
    { 
     if (_executeMethod != null) 
     { 
      _executeMethod(parameter); 
     } 
    } 

    public void RaiseCanExecuteChanged() 
    { 
     OnCanExecuteChanged(EventArgs.Empty); 
    } 

    #endregion Public Methods 

    #region Protected Methods 

    protected virtual void OnCanExecuteChanged(EventArgs e) 
    { 
     var handler = CanExecuteChanged; 
     if (handler != null) 
     { 
      handler(this, e); 
     } 
    } 

    #endregion Protected Methods 
} 
+0

我不喜歡通用部分(默認),但我喜歡這個示例! – 2012-08-22 02:00:15

+0

@ JerryNixon-MSFT - 你爲什麼不「像通用部分」?如果你想避免泛型,你必須通過執行Action 或Action 然後執行所有關聯的強制轉換和類型檢查以獲得相同結果 – 2013-08-03 16:31:57

+0

@Shawn Kendrot - 在ICommand中使代碼更復雜。 CanExecute,你可以替換那個潛在的昂貴的try ... catch塊,你能不能'返回CanExecute(參數爲T)',然後在'CanExecute'中添加一個'parameter == null'的檢查? – 2013-08-03 16:33:54

3

退房RelayCommand類(只有METRO代碼)。 NotifyPropertyChanged類可以找到hereNotifyPropertyChanged類僅用於允許在CanExecute上進行綁定並使用RaiseCanExecuteChanged進行更新。

原來的繼電器命令類可以發現here

2

遺憾的是,似乎沒有要實現它爲你的本地類。如果您想自己實現接口,則接口不會過於複雜,並且流行的工具包包括其自己的RelayCommand版本。您可以通過右鍵單擊引用並選擇「管理NuGet包」來將MVVM Lite添加到您的項目中。如果您沒有此選項,請在工具 - >擴展和更新下啓用Nuget。

0

我一直在尋找一個XAML-MVVM命令的最小端到端實現,但還沒有找到它。

因此,下面#Rico的回答結束了以下作爲一個最小的RelayCommand工作。我在一個大型項目中使用了類似的最小版本。

public class RelayCommand : System.Windows.Input.ICommand { 

    readonly Action<object> execute; 

    public RelayCommand(Action<object> execute) { 
     this.execute = execute; 
    } 

    public bool CanExecute(object parameter) { 
     return true; 
    } 

    public event EventHandler CanExecuteChanged; 

    public void Execute(object parameter) { 
     this.execute(parameter); 
    } 
} 

較大RelayCommand類好像在CanExecuteCanExecuteChanged提供更多的控制,但你並不需要一個上手 - 你可能不需要它。

要在視圖模型使用它:

class ViewModel : INotifyPropertyChanged { 

    << ... snip VM properties and notifications ...>> 

    public RelayCommand DoSomethingCommand { 
     get { 
      return new RelayCommand(param => { 
       this.DoSomething(param as AType); 
       Debug.WriteLine("Command Executed"); 
      }); 
     } 

    } 
} 

(我們並不需要INotifyPropertyChanged的有關命令,但任何視圖模型通常實現它。)

最後,XAML。 ..

<Grid> 
     <!-- Set the data context here, for illustration. --> 
     <Grid.DataContext> 
      <local:ViewModel/> 
     </Grid.DataContext> 
     <!-- A sample control bind to a property --> 
     <TextBlock 
      Text="{Binding AProp}"/> 
     <!-- Bind a command --> 
     <Button Command="{Binding DoSomethingCommand}" CommandParameter="foo">Change!</Button> 
    </Grid> 
0

我發現這真的是很好的例子,在 https://code.msdn.microsoft.com/windowsapps/Working-with-ICommand-690ba1d4

<Page.Resources> 
     <local:MyCommandsCollection x:Key="MyCommands" /> 
</Page.Resources> 

    <Button Width="280" 
      Height="59" 
      Margin="513,280,0,0" 
      HorizontalAlignment="Left" 
      VerticalAlignment="Top" 
      Command="{Binding MyFirstCommand}" 
      CommandParameter="{Binding Text, 
             ElementName=myTextBox}" 
      Content="Execute Command" /> 


public class MyCommandsCollection 
{ 
    public MyCommand MyFirstCommand 
    { 
     get { return new MyCommand(); } 
    } 
} 

public class MyCommand : ICommand 
    { 
     public bool CanExecute(object parameter) 
     { 
      return true; 
     } 

     public event EventHandler CanExecuteChanged; 

     public async void Execute(object parameter) 
     { 
      MessageDialog message = new MessageDialog( 
       "The command is executing, the value of the TextBox is " + parameter as String); 
      await message.ShowAsync(); 
     } 
    } 

我用x:Bind試了一下,它工作的很好。我需要的只是公開ViewModel中的一個屬性,它返回一個「MyCommand」類的新實例,這很好。

由於我在我的XAML中設置了DataContext,因此我不需要混淆任何「MyCommandCollection」的東西。耶編譯綁定。