tutorial que programacion conceptos codeproject basico c# .net wpf mvvm icommand
example

c# - que - Implementación WPF ICommand MVVM



tutorial mvvm wpf c# (4)

@Carlo Me gusta mucho su implementación de esto, pero quería compartir mi versión y cómo usarla en mi ViewModel

Primero implementa ICommand

public class Command : ICommand { public delegate void ICommandOnExecute(); public delegate bool ICommandOnCanExecute(); private ICommandOnExecute _execute; private ICommandOnCanExecute _canExecute; public Command(ICommandOnExecute onExecuteMethod, ICommandOnCanExecute onCanExecuteMethod = null) { _execute = onExecuteMethod; _canExecute = onCanExecuteMethod; } #region ICommand Members public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public bool CanExecute(object parameter) { return _canExecute?.Invoke() ?? true; } public void Execute(object parameter) { _execute?.Invoke(); } #endregion }

Tenga en cuenta que he eliminado el parámetro de ICommandOnExecute y ICommandOnCanExecute y he añadido un valor nulo al constructor

Luego para usar en ViewModel

public Command CommandToRun_WithCheck { get { return new Command(() => { // Code to run }, () => { // Code to check to see if we can run // Return true or false }); } } public Command CommandToRun_NoCheck { get { return new Command(() => { // Code to run }); } }

Simplemente me parece más limpio ya que no necesito asignar variables y luego crear instancias, todo hecho de una vez.

Entonces, en esta implementación particular de MVVM que estoy haciendo, necesito varios comandos. Realmente me cansé de implementar las clases de ICommand una a una, así que se me ocurrió una solución, pero no sé lo bueno que es, por lo que la contribución de cualquier experto de WPF será muy apreciada. Y si pudiera proporcionar una mejor solución, ¡aún mejor!

Lo que hice fue una única clase ICommand y dos delegados que toman un objeto como parámetro, un delegado es nulo (para OnExecute), el otro bool (para OnCanExecute). Entonces en el constructor de mi ICommand (que es llamado por la clase ViewModel) envío los dos métodos, y en cada método ICommand invoco los métodos de los delegados.

Funciona muy bien, pero no estoy seguro si esta es una mala manera de hacerlo, o si hay una mejor manera. A continuación se muestra el código completo, cualquier contribución será muy apreciada, incluso negativa, pero sea constructivo.

¡¡Gracias!!

ViewModel:

public class TestViewModel : DependencyObject { public ICommand Command1 { get; set; } public ICommand Command2 { get; set; } public ICommand Command3 { get; set; } public TestViewModel() { this.Command1 = new TestCommand(ExecuteCommand1, CanExecuteCommand1); this.Command2 = new TestCommand(ExecuteCommand2, CanExecuteCommand2); this.Command3 = new TestCommand(ExecuteCommand3, CanExecuteCommand3); } public bool CanExecuteCommand1(object parameter) { return true; } public void ExecuteCommand1(object parameter) { MessageBox.Show("Executing command 1"); } public bool CanExecuteCommand2(object parameter) { return true; } public void ExecuteCommand2(object parameter) { MessageBox.Show("Executing command 2"); } public bool CanExecuteCommand3(object parameter) { return true; } public void ExecuteCommand3(object parameter) { MessageBox.Show("Executing command 3"); } }

Yo ordeno:

public class TestCommand : ICommand { public delegate void ICommandOnExecute(object parameter); public delegate bool ICommandOnCanExecute(object parameter); private ICommandOnExecute _execute; private ICommandOnCanExecute _canExecute; public TestCommand(ICommandOnExecute onExecuteMethod, ICommandOnCanExecute onCanExecuteMethod) { _execute = onExecuteMethod; _canExecute = onCanExecuteMethod; } #region ICommand Members public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public bool CanExecute(object parameter) { return _canExecute.Invoke(parameter); } public void Execute(object parameter) { _execute.Invoke(parameter); } #endregion }


Acabo de crear un pequeño example muestra cómo implementar comandos en convención sobre el estilo de configuración. Sin embargo, requiere que Reflection.Emit () esté disponible. El código de soporte puede parecer un poco raro, pero una vez escrito puede usarse muchas veces.

Rompecabezas:

public class SampleViewModel: BaseViewModelStub { public string Name { get; set; } [UiCommand] public void HelloWorld() { MessageBox.Show("Hello World!"); } [UiCommand] public void Print() { MessageBox.Show(String.Concat("Hello, ", Name, "!"), "SampleViewModel"); } public bool CanPrint() { return !String.IsNullOrEmpty(Name); } }

}

ACTUALIZACIÓN : ahora parece que existen algunas bibliotecas como http://www.codeproject.com/Articles/101881/Executing-Command-Logic-in-a-View-Model que resuelven el problema del código estándar de ICommand.


Esto es casi idéntico a cómo Karl Shifflet demostró un RelayCommand , donde Execute dispara una Action<T> predeterminada Action<T> . Una excelente solución, si me preguntas.

public class RelayCommand : ICommand { private Predicate<object> _canExecute; private Action<object> _execute; public RelayCommand(Predicate<object> canExecute, Action<object> execute) { this._canExecute = canExecute; this._execute = execute; } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public bool CanExecute(object parameter) { return _canExecute(parameter); } public void Execute(object parameter) { _execute(parameter); } }

Esto podría ser usado como ...

public class MyViewModel { private ICommand _doSomething; public ICommand DoSomethingCommand { get { if (_doSomething == null) { _doSomething = new RelayCommand( p => this.CanDoSomething, p => this.DoSomeImportantMethod()); } return _doSomething; } } }

Lee mas:
Josh Smith (introductor de RelayCommand ): Patrones - Aplicaciones WPF con el patrón de diseño MVVM


He escrito este article sobre la interfaz de ICommand.

La idea: crear un comando universal que requiera dos delegados: uno se llama cuando se invoca ICommand.Execute (object param) , el segundo comprueba el estado de si se puede ejecutar el comando (ICommand.CanExecute (object param)) .

Requiere el método para cambiar el evento CanExecuteChanged . Se llama desde los elementos de la interfaz de usuario para cambiar el comando CanExecute() estado.

public class ModelCommand : ICommand { #region Constructors public ModelCommand(Action<object> execute) : this(execute, null) { } public ModelCommand(Action<object> execute, Predicate<object> canExecute) { _execute = execute; _canExecute = canExecute; } #endregion #region ICommand Members public event EventHandler CanExecuteChanged; public bool CanExecute(object parameter) { return _canExecute != null ? _canExecute(parameter) : true; } public void Execute(object parameter) { if (_execute != null) _execute(parameter); } public void OnCanExecuteChanged() { CanExecuteChanged(this, EventArgs.Empty); } #endregion private readonly Action<object> _execute = null; private readonly Predicate<object> _canExecute = null; }