mvvmlight galasoft c# wpf mvvm-light

c# - galasoft - ICommand CanExecute no se desencadena después de PropertyChanged?



mvvm light uwp (4)

El problema es que ICommand Property TestrunStartCommand siempre devuelve un nuevo objeto de comando cada vez que se accede a él.

Una solución simple es crear el objeto ICommand una vez y usarlo una y otra vez.

private ICommand _testRunCommand = null; public ICommand TestrunStartCommand { get { return _testRunCommand ?? (_testRunCommand = new RelayCommand(TestrunStartExecute, () => !IsTestrunInProgress)); } }

Esta fue una solución bastante simple y funcionó para mí.

Tengo una aplicación WPF que muestra un botón vinculado a un comando como ese:

<Button Command="{Binding Path=TestrunStartCommand}" Content="GO!">

El comando se define así:

public ICommand TestrunStartCommand { get { return new RelayCommand(TestrunStartExecute, () => !IsTestrunInProgress); } } public bool IsTestrunInProgress { get{ return _isTestrunInProgress; } set{ _isTestrunInProgress = value; RaisePropertyChanged(IsTestrunInProgressPropertyName); } }

El problema es que el botón no se habilitará inmediatamente después de establecer IsTestrunInProgress en falso, pero solo después de hacer clic dentro de la ventana de la aplicación .

¿Podrías ayudarme a entender este comportamiento y mostrarme cómo solucionarlo?

Lectura adicional: patrón de comando wpf: ¿cuándo se realiza la consulta canexecute?


Esto es tan importante y fácil de perder, estoy repitiendo lo que @Samir dijo en un comentario. Mr Laurent Bugnion escribió en su blog :

En WPF 4 y WPF 4.5, sin embargo, hay una trampa: el CommandManager dejará de funcionar después de actualizar MVVM Light a V5. Lo que observará es que sus elementos de IU (botones, etc.) dejarán de deshabilitarse / habilitarse cuando el delegado CanExecute de RelayCommand devuelva falso.

Si tiene prisa, aquí está la solución: en cualquier clase que use RelayCommand, reemplace la línea que dice:

using GalaSoft.MvvmLight.Command;

con:

using GalaSoft.MvvmLight.CommandWpf;


La interfaz de ICommand expone un evento ICommand.CanExecuteChanged que se utiliza para informar a la IU cuando se debe volver a determinar el estado IsEnabled de los componentes de la IU dirigidos por comandos.

Dependiendo de la implementación del RelayCommand que esté utilizando, es posible que deba plantear este evento; Muchas implementaciones exponen un método como RelayCommand.RaiseCanExecuteChanged() que puede invocar para forzar la actualización de la interfaz de usuario.

Algunas implementaciones de RelayCommand utilizan CommandManager.RequerySuggested , en cuyo caso deberá llamar a CommandManager.InvalidateRequerySuggested() para forzar la actualización de la interfaz de usuario.

Para resumir, tendrá que llamar a uno de estos métodos desde el organizador de su propiedad.

Actualizar

Como el estado del botón se está determinando cuando el foco activo está cambiando, creo que se está utilizando el CommandManager . Entonces, en el establecimiento de su propiedad, después de asignar el campo de respaldo, invoque CommandManager.InvalidateRequerySuggested() .

Actualización 2

La implementación de RelayCommand es del juego de herramientas ligero de MVVM. Cuando se consume desde WPF / .NET, la implementación ajusta los métodos y eventos expuestos desde CommandManager . Esto significará que estos comandos funcionan automágicamente en la mayoría de las situaciones (cuando se modifica la UI o se cambia el elemento enfocado). Pero en algunos casos, como este, tendrá que forzar manualmente el comando para volver a consultar. La forma correcta de hacerlo utilizando esta biblioteca sería llamar al método RaiseCanExecuteChanged() en RelayCommand .


Puedes probar con CommandManager.InvalidateRequerySuggested() .

De todos modos, esto no me ayudó a veces en el pasado. Para mí, la mejor solución resultó ser enlazar la propiedad booleana a la propiedad de dependencia Button.IsEnabled .

En tu caso algo como

IsEnabled={Binding IsTestrunInProgress}