2010-02-25 17 views
19

Mi aplicación está escrita usando el patrón MVVM en WPF, y todos mis botones usan enlaces de comando para ejecutar código en mi modelo. Todos los comandos tienen código en CanExecute para determinar el estado habilitado del botón enlazado. La lógica funciona perfectamente, pero en todos los casos, la GUI permanece en estado desactivado a menos que haga clic en otro lugar en la GUI.Problema raro donde el botón no se vuelve a habilitar a menos que se haga clic en el mouse

Por ejemplo, tengo un botón llamado Discard Candy. Cuando hago clic en este botón, se inicia un proceso en una secuencia de subprocesos, que establece una propiedad bool llamada Ejecutando en true. Dado que el método CanExecute para el mando de Descarte caramelo ve algo como esto

public bool CanExecute(object parameter) 
{ 
    return !Running; 
} 

el botón se desactivará una vez que el proceso se inicia. El problema es que cuando el proceso finaliza, Running se establece en false, pero la GUI no se actualiza, es decir, Discard Candy no se vuelve a habilitar.

Sin embargo, si hago clic en cualquier parte de la GUI, como en la ventana o la barra de título, el botón Discard Candy se activa de repente. Entonces la lógica funciona, pero está sucediendo algo que simplemente no entiendo. ¿Puede alguien explicarme este comportamiento?

EDIT - hasta ahora, parece que CommandManager.InvalidateRequerySuggested no ha ayudado a las personas. Voy a intentarlo, pero por el momento soy un poco cauteloso. Seguí los enlaces recomendados y, al hacerlo, decidí leer más sobre el juego de herramientas ligeras MVVM. Suena muy nice - ¿alguien lo ha usado aquí y ha podido confirmar que no muestra el problema que he estado viendo hasta ahora? Aunque planeo probar el juego de herramientas ligero MVVM en la próxima gran revolución. de mi aplicación, no quiero rehacer todos los comandos que tengo actualmente, por lo que es probable que comience con CommandManager.InvalidateRequerySuggested para que todos podamos obtener otro punto de datos con respecto a su utilidad.

editar # 2 - muy interesante, el kit de herramientas de luz MVVM realidad se basa en CommandManager.InvalidateRequerySuggested con el fin de apoyar la capacidad de la interfaz de usuario para desactivar/vuelva a activar los comandos. El autor dice:

"Hablando estrictamente, en WPF, y si su comando está vinculado a un control que es visto por el CommandManager, no debería tener que plantear el evento CanExecuteChanged usted mismo. Puede dejar que el CommandManager maneje el situación. Dicho esto, los eventos externos también pueden cambiar el estado de la interfaz de usuario. Imaginemos que la IU debe habilitarse de 9 a.m. a 5 p.m., y luego deshabilitada por la noche. El usuario no está desencadenando la IU, por lo que el código debe solicitar (cortésmente) que el Administrador de comandos vuelve a consultar el estado de los comandos. Esto se hace llamando al método InvalidateRequerySuggested en el Administrador de comandos. Y como lo has adivinado, el método de la clase RaiseCanExecuteChanged RelayCommand hace precisamente eso. "

+0

¿Puedes mostrar el código que establece la ejecución en falso? ¿Está en la devolución de llamada una vez que se completa el hilo? –

+0

¿Estás generando CanExecuteChanged para el comando cuando configuras la ejecución? – itowlson

+0

@John: Running se establece en falso una vez que se haya completado el flujo de trabajo, que se conoce cuando se establece el evento especificado. @itowlson: Tenía la impresión de que todo funcionaría "mágicamente". Cuando estaba aprendiendo esto, puse un punto de interrupción en CanExecute y siempre me pegaban ... pero me imagino que esto es solo porque cuando presiono F5, la GUI vuelve a pintar, lo que hace que CanExecute vuelva a llamar. ¡Tonto de mí! – Dave

Respuesta

17

WPF no actualiza los controles vinculados a comandos a menos que tenga un motivo para. Al hacer clic en la GUI, WPF se actualiza para que la actualización funcione.

Puede provocar manualmente una actualización de los controles vinculados al comando llamando al CommandManager.InvalidateRequerySuggested.

+1

Gracias, Cameron, voy a dar una oportunidad. ¿Es difícil poner esto en un temporizador con un intervalo razonable? – Dave

+1

Probablemente. ¿Puedes llamar después de que hayas terminado de procesar? –

+7

He visto el mismo comportamiento que Dave y la ejecución de CommandManager.InvalidateRequerySuggested no me ayudó. Espero que alguien aquí pueda darnos una idea de por qué a veces sucede esto. – Kilhoffer

0

A veces, establecer el foco en el control principal hace que el CommandManager active CanExecute.Intente lo siguiente después de establecer Correr en false:

... 
Running = false; 
parentControl.Focusable = true; 
parentControl.Focus(); 
2

Mi problema parecía estar ligado a la unión de comandos - He utilizado el RelayCommand como lo hacen con frecuencia, pero la prestación de un botón simplemente no era correcto hasta que hace clic en un ventana.

Extracción del código CanExecute del CommandBinding y el uso de una propiedad IsEnabled vez solucionado el problema sin un dolor de cabeza - que sólo tuvo siempre hasta que probé este entre tantas otras cosas que podrían haber sido la peoblem ...

Cuestiones relacionadas