2009-08-27 14 views
111

tengo un Menu donde cada MenuItem en la jerarquía tiene su Command propiedad establecida en una RoutedCommand he definido. El CommandBinding asociado proporciona una devolución de llamada para la evaluación de CanExecute que controla el estado habilitado de cada MenuItem.WPF - Cómo forzar un comando para volver a evaluar 'CanExecute' a través de sus CommandBindings

Este funciona casi. Los elementos de menú inicialmente aparecen con los estados habilitados y deshabilitados correctos. Sin embargo, cuando cambian los datos que utiliza mi devolución de 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 UI.

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 utiliza nuevamente cuando hago clic o escribo en el control (supongo que se activa en la entrada porque el mouse no causa la actualización).

Respuesta

149
No

la más bonita en el libro, pero se puede utilizar el Administrador de comandos para invalidar toda CommandBinding:

CommandManager.InvalidateRequerySuggested(); 

Ver más información sobre MSDN

+0

Gracias, funcionó bien. Hay un ligero retraso en la IU, pero no estoy demasiado preocupado por eso.Además, elevé tu respuesta de inmediato, luego volví a votar para ver si funcionaba. Ahora que está funcionando, no puedo volver a aplicar el voto nuevamente. No estoy seguro de por qué SO tiene esa regla en su lugar. –

+4

Edité tu respuesta para volver a aplicar mi voto. No cambié nada en la edición. Gracias de nuevo. –

+0

jaja ok :) gracias! – Arcturus

72

Para cualquier persona que viene a través de esta tarde; Si está usando MVVM y Prism, la implementación de de Prism DelegateCommand proporciona un método .RaiseCanExecuteChanged() para hacerlo.

+10

Este patrón también se encuentra en otras bibliotecas de MVVM, p.ej MVVM Light. –

+1

A diferencia de Prism, el código fuente de MVVM Light v5 indica que 'RaiseCanExecuteChanged()' simplemente llama a 'CommandManager.InvalidateRequerySuggested()'. – Peter

+3

una nota al lado de MVVM Light en WPF, necesita usar el espacio de nombre GalaSoft.MvvmLight.CommandWpf ya que GalaSoft.MvvmLight.Command causará problemas http://www.mvvmlight.net/installing/changes#v5_0_2 – fuchs777

21

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

He usado MVVM Helper's Delegando comando, que se ve a continuación (lo he ajustado un poco para nuestra solicitud). usted tiene que llamar command.RaiseCanExecuteChanged() de 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); 
} 
+0

Esto funcionó mejor para mi. Gracias. –

+2

Solo un FYI Comenté CommandManager.RequerySuggested + = value; Obtuve una evaluación casi constante/en bucle de mi código CanExecute por algún motivo. De lo contrario, la solución funcionó como se esperaba. ¡Gracias! – robaudas

2

he implementado una solución para manejar la dependencia de la propiedad sobre los comandos, aquí el enlace https://stackoverflow.com/a/30394333/1716620

gracias a que usted va a terminar con 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 } 
); 
4

Si ha rodado su propia clase que implementa ICommand se puede perder una gran cantidad de las actualizaciones de estado automáticas lo que obligó a depender de restauración manual de más de caso que fuera necesaria. 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 utilizar la siguiente:

public event EventHandler CanExecuteChanged 
    { 
     add { CommandManager.RequerySuggested += value; } 
     remove { CommandManager.RequerySuggested -= value; } 
    } 

    public void RaiseCanExecuteChanged() 
    { 
     CommandManager.InvalidateRequerySuggested(); 
    } 

esta manera se unen a los suscriptores CommandManager en lugar de su clase y pueden participar adecuadamente en los cambios de estado de comando.

+0

Directo, al punto, y permite a las personas tener control sobre sus implementaciones de ICommand. –

Cuestiones relacionadas