2012-08-14 16 views

Respuesta

19

Mi favorito de todos los tiempos tiene que ser el DelegateCommand proporcionado por el equipo de PnP. Se le permite crear un comando escrito:

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

También permite que proporciona una manera de provocar el evento CanExecuteChanged (para activar/desactivar el comando)

MyCommand.RaiseCanExecuteChanged(); 

Aquí está el código:

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

No me gusta la parte genérica (por defecto) pero me gusta la muestra! –

+0

@ JerryNixon-MSFT: ¿por qué no "[no] me gusta la parte genérica"? Si desea evitar el genérico, deberá complicar el código tomando la Acción , o la Acción y luego realizar todas las operaciones de conversión y verificación de tipos asociadas para obtener el mismo resultado –

+0

@Shawn Kendrot - en ICommand. CanExecute, podrías reemplazar ese potencialmente costoso try ... catch block, ¿no podrías hacer 'return CanExecute (parámetro como T)', luego en 'CanExecute', agregar una verificación para' parameter == null'? –

3

Consulte RelayCommand clase (solo código METRO). La clase NotifyPropertyChanged se puede encontrar here. La clase NotifyPropertyChanged solo se usa para permitir enlaces en CanExecute y la actualiza con RaiseCanExecuteChanged.

La clase original mando del relé se puede encontrar here

2

Por desgracia, no parece ser una clase nativa que lo implementa para usted. La interfaz no es demasiado complicada si quiere implementarla usted mismo, y el popular MVVM Lite toolkit incluye su propia versión de RelayCommand. Puede agregar MVVM Lite a su proyecto haciendo clic derecho en Referencias y seleccionando "Administrar paquetes NuGet". Si no tiene esta opción, habilite Nuget en Herramientas -> Extensiones y actualizaciones.

0

He estado buscando una implementación end-to-end mínima de un comando XAML-MVVM, y todavía no lo he encontrado.

Entonces, siguiendo la respuesta de # Rico terminé con lo siguiente como un RelayCommand mínimo que funciona. Utilizo una versión mínima similar en un proyecto grande.

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

La clase más grande RelayCommand parece proporcionar un mayor control sobre CanExecute y CanExecuteChanged, pero no es necesario que para empezar - y puede que no lo necesita en absoluto.

para usarlo en un modelo de vista:

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

    } 
} 

(No necesitamos la INotifyPropertyChanged para el comando, pero cualquier modelo de vista normalmente implementa.)

Por último, el 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

yo encontramos este muy buen ejemplo en 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(); 
     } 
    } 

Probé esto con x: Bind y funciona muy bien. Todo lo que necesito es exponer una propiedad en mi ViewModel que devuelva una nueva instancia de la clase "MyCommand" y todo está bien.

Como estoy configurando el DataContext en mi XAML, no tuve que meterme con ninguna de las cosas de "MyCommandCollection". Yay compilado vinculante.

Cuestiones relacionadas