Declaración del problema.
Como parte del desarrollo de una aplicación, se requería implementar el siguiente esquema:
- El método asincrónico solicita datos
- El usuario ingresa datos desde el teclado
- El método recibe el resultado de entrada como resultado de la función y continúa desde el mismo lugar
Requisito adicional: no cree ventanas adicionales.
Parecería simple? Resultó ser realmente simple. Pero lo primero es lo primero.
Solución
El primer intento de hacerlo de frente y sin buscar en Internet condujo a un bloqueo de la transmisión principal y, por lo tanto, no sirvió de nada. Y estaba a punto de usar ShowDialog, cuando me encontré con un artículo . El autor observó cómo se hace ShowDialog en WPF. Lo que necesitas!
En su artículo, sugiere crear su propia implementación del método ShowDialog
[DllImport("user32")] internal static extern bool EnableWindow(IntPtr hwnd, bool bEnable); public void ShowModal() { IntPtr handle = (new WindowInteropHelper(Application.Current.MainWindow)).Handle; EnableWindow(handle, false); DispatcherFrame frame = new DispatcherFrame(); this.Closed += delegate { EnableWindow(handle, true); frame.Continue = false; }; Show(); Dispatcher.PushFrame(frame); }
No necesito un bloqueo de ventana, ya que todo se muestra en una ventana, y también se requiere un valor de retorno. Eliminamos demasiado, agregamos el correcto ...
public string GetInput() { var frame = new DispatcherFrame(); ButtonClicked += () => { frame.Continue = false; }; Dispatcher.PushFrame(frame); return Text; }
Dispatcher.PushFrame(frame)
evita que el método frame.Continue
GetInput()
hasta frame.Continue
vuelve false
. Cuando se inicia un nuevo marco, el bucle principal se detiene y se inicia uno nuevo. Este bucle procesa los mensajes del sistema, mientras que el punto de ejecución en el bucle principal no se mueve más. Cuando salimos del marco actual ( frame.Continue = false
), el bucle principal continúa trabajando desde el mismo lugar.
Ahora solo queda comprobar el rendimiento.
En MainWindow, cree un botón y cuelgue un controlador en él, lo que iniciará la tarea, en la que pasaremos a la entrada del teclado.
Código de manejador:
public RelayCommand ButtonClick => new RelayCommand(() => { Task.Factory.StartNew(() => {
Usé esta solución para ingresar captcha y código adicional para la autenticación de dos factores. Pero puede haber una gran cantidad de aplicaciones.
! El código de muestra contiene violaciones del principio mvvm y no pegues fuerte diseño faltante
Código fuente de Github: prueba de concepto
Enlaces utiles
Artículo "ShowDialog personalizado"
Descripción escasa de la clase DispatcherFrame utilizando traducción automática
En este artículo, se espera la finalización a través de esperar .