WPF – Cómo forzar a un comando a volver a evaluar ‘CanExecute’ a través de sus Enlaces de Comando

Tengo un Menu donde cada elemento de Menu en la jerarquía tiene su propiedad de Command establecida en un RoutedCommand que he definido. El CommandBinding asociado proporciona una callback para la evaluación de CanExecute que controla el estado habilitado de cada elemento de MenuItem .

Esto casi funciona Los elementos de menú inicialmente aparecen con los estados habilitados y deshabilitados correctos. Sin embargo, cuando CanExecute los datos que utiliza mi CanExecute llamada CanExecute , necesito el comando para volver a solicitar un resultado de mi callback para que este nuevo estado se refleje en la IU.

No parece haber ningún método público en RoutedCommand o CommandBinding para esto.

Tenga en cuenta que la callback se usa nuevamente cuando hago clic o escribo en el control (supongo que se activa en la entrada porque el mouse no causa la actualización).

No es el más bonito del libro, pero puede usar CommandManager para invalidar todo el enlace de comandos:

 CommandManager.InvalidateRequerySuggested(); 

Ver más información en MSDN

Para cualquiera que se encuentre con esto más tarde; Si está utilizando MVVM y Prism, la implementación DelegarCommand de Prism de ICommand proporciona un método .RaiseCanExecuteChanged() para hacer esto.

No pude usar CommandManager.InvalidateRequerySuggested(); porque estaba recibiendo un golpe de rendimiento.

He usado el comando Delegar de MVVM Helper , que se ve a continuación (lo pellizqué un poco para nuestro pedido). tienes que llamar a command.RaiseCanExecuteChanged() desde VM

 public event EventHandler CanExecuteChanged { add { _internalCanExecuteChanged += value; CommandManager.RequerySuggested += value; } remove { _internalCanExecuteChanged -= value; CommandManager.RequerySuggested -= value; } } ///  /// This method can be used to raise the CanExecuteChanged handler. /// This will force WPF to re-query the status of this command directly. ///  public void RaiseCanExecuteChanged() { if (canExecute != null) OnCanExecuteChanged(); } ///  /// This method is used to walk the delegate chain and well WPF that /// our command execution status has changed. ///  protected virtual void OnCanExecuteChanged() { EventHandler eCanExecuteChanged = _internalCanExecuteChanged; if (eCanExecuteChanged != null) eCanExecuteChanged(this, EventArgs.Empty); } 

Si ha lanzado su propia clase que implementa ICommand , puede perder muchas de las actualizaciones de estado automáticas que lo obligan a confiar en la actualización manual más de lo que debería ser necesario. También puede romper InvalidateRequerySuggested() . El problema es que una implementación simple de ICommand no puede vincular el nuevo comando al CommandManager .

La solución es usar lo siguiente:

  public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public void RaiseCanExecuteChanged() { CommandManager.InvalidateRequerySuggested(); } 

De esta forma, los suscriptores se conectan a CommandManager lugar de su clase y pueden participar de forma adecuada en los cambios de estado del comando.

Implementé una solución para manejar la dependencia de propiedades en los comandos, aquí el enlace https://stackoverflow.com/a/30394333/1716620

gracias a eso terminarás teniendo un comando como este:

 this.SaveCommand = new MyDelegateCommand(this, //execute () => { Console.Write("EXECUTED"); }, //can execute () => { Console.Write("Checking Validity"); return PropertyX!=null && PropertyY!=null && PropertyY.Length < 5; }, //properties to watch (p) => new { p.PropertyX, p.PropertyY } );