.net - WPF-Cómo forzar a un comando a volver a evaluar ''CanExecute'' a través de sus Enlaces de Comando
command commandbinding (5)
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<MyViewModel>(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 }
);
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 devolución de llamada 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 devolución de llamada 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 devolución de llamada 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
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;
}
}
/// <summary>
/// This method can be used to raise the CanExecuteChanged handler.
/// This will force WPF to re-query the status of this command directly.
/// </summary>
public void RaiseCanExecuteChanged()
{
if (canExecute != null)
OnCanExecuteChanged();
}
/// <summary>
/// This method is used to walk the delegate chain and well WPF that
/// our command execution status has changed.
/// </summary>
protected virtual void OnCanExecuteChanged()
{
EventHandler eCanExecuteChanged = _internalCanExecuteChanged;
if (eCanExecuteChanged != null)
eCanExecuteChanged(this, EventArgs.Empty);
}
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.
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.