2012-08-14 4 views

Antwort

19

Mein Favorit aller Zeiten ist der DelegateCommand, der vom PnP-Team bereitgestellt wird. Es ermöglicht Ihnen, eine typisierte Befehl zu erstellen:

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

Es ermöglicht auch eine Möglichkeit bietet, die CanExecuteChanged Ereignis (deaktivieren/aktivieren Sie den Befehl)

MyCommand.RaiseCanExecuteChanged(); 

Hier ist der Code zu erhöhen:

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

Ich mag nicht den generischen Teil (als Standard), aber ich mag das Beispiel! –

+0

@ JerryNixon-MSFT - warum "nicht [wie] der generische Teil"? Wenn Sie das Generische vermeiden möchten, müssen Sie den Code komplizierter machen, indem Sie die Aktion oder Aktion ausführen und dann alle zugehörigen Casting- und Typprüfungen durchführen, um das gleiche Ergebnis zu erhalten. –

+0

@Shawn Kendrot - in ICommand. CanExecute, Sie könnten diesen potenziell teuren try ... catch Block ersetzen, könnten Sie nicht einfach 'CanExecute (Parameter als T)' 'zurückgeben, dann in' CanExecute', fügen Sie einen Haken für 'parameter == null'? –

3

Auschecken RelayCommand Klasse (nur METRO-Code). Die NotifyPropertyChanged Klasse kann here gefunden werden. Die Klasse NotifyPropertyChanged wird nur verwendet, um Bindungen unter CanExecute zuzulassen und sie mit RaiseCanExecuteChanged zu aktualisieren.

Der ursprüngliche Befehl Klasse Relais kann here

2

Leider finden dort keine native Klasse zu sein scheint, dass es für Sie implementiert. Die Schnittstelle ist nicht übermäßig kompliziert, wenn Sie sie selbst implementieren möchten, und das populäre MVVM Lite Toolkit enthält eine eigene Version von RelayCommand. Sie können MVVM Lite zu Ihrem Projekt hinzufügen, indem Sie mit der rechten Maustaste auf Verweise klicken und "NuGet-Pakete verwalten" auswählen. Wenn Sie diese Option nicht haben, aktivieren Sie Nuget unter Tools -> Erweiterungen und Updates.

0

Ich habe nach einer minimalen Ende-zu-Ende-Implementierung eines XAML-MVVM-Befehls gesucht und es noch nicht gefunden.

Also, nach # Ricos Antwort endete ich mit dem folgenden als ein minimaler RelayCommand, der funktioniert. Ich benutze eine ähnliche minimale Version in einem großen Projekt.

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

Je größer RelayCommand Klasse scheint mehr Kontrolle über CanExecute und CanExecuteChanged, zur Verfügung zu stellen, aber Sie brauchen nicht, um loszulegen - und Sie können es nicht brauchen.

Um es in einem View-Modell zu verwenden:

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

    } 
} 

(Wir tun die INotifyPropertyChanged für den Befehl nicht brauchen, aber jede Ansicht Modell es in der Regel implementiert.)

Schließlich ist die 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

ich fand diese wirklich gutes Beispiel bei 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(); 
     } 
    } 

Ich versuchte es mit x: Bind und es funktioniert gut. Alles, was ich brauche, ist eine Eigenschaft in meinem ViewModel verfügbar zu machen, die eine neue Instanz der Klasse "MyCommand" zurückgibt, und alles ist gut.

Da ich den DataContext in meinem XAML setze, musste ich mich nicht mit irgendwelchen der "MyCommandCollection" Zeug beschäftigen. Yay kompiliert verbindlich.