Window.ShowDialog () analógico em C # WPF ou lidar com DispatcherFrame

Declaração do problema


Como parte do desenvolvimento de um aplicativo, foi necessário implementar o seguinte esquema:


  1. O método assíncrono solicita dados
  2. O usuário digita dados do teclado
  3. O método recebe o resultado da entrada como resultado da execução da função e continua do mesmo local

Requisito adicional: Não crie janelas adicionais.


Parece simples? Acabou sendo muito simples. Mas as primeiras coisas primeiro.


Solução


A primeira tentativa de fazê-lo de frente e sem pesquisar na Internet levou a um bloqueio do fluxo principal e, portanto, não adiantou. E eu estava prestes a usar o ShowDialog, como me deparei com um artigo . O autor analisou como o ShowDialog é feito no WPF. O que você precisa!


Em seu artigo, ele sugere criar sua própria implementação do 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); } 

Não preciso de um bloqueio de janela, pois tudo é mostrado em uma janela e também é necessário um valor de retorno. Removemos um pouco demais, adicionamos o correto ...


  public string GetInput() { var frame = new DispatcherFrame(); ButtonClicked += () => { frame.Continue = false; }; Dispatcher.PushFrame(frame); return Text; } 

Dispatcher.PushFrame(frame) impede que o método GetInput() até o frame.Continue se tornar false . Quando um novo quadro é iniciado, o loop principal faz uma pausa e um novo é iniciado. Esse loop processa as mensagens do sistema, enquanto o ponto de execução no loop principal não se move mais. Quando saímos do quadro atual ( frame.Continue = false ), o loop principal continua funcionando do mesmo local.


Agora resta apenas verificar o desempenho.


No MainWindow, crie um botão e coloque um manipulador que iniciará a tarefa, na qual passaremos para a entrada do teclado.


Código do manipulador:


  public RelayCommand ButtonClick => new RelayCommand(() => { Task.Factory.StartNew(() => { //   Thread.Sleep(1000); //  -  var control = new PopupControlModel(); //  ,      Result = control.GetInput(); //    Thread.Sleep(2000); }); }); } 

Usei esta solução para inserir captcha e código adicional para autenticação de dois fatores. Mas pode haver um grande número de aplicativos.


! O código de amostra contém violações do princípio mvvm e não bata forte falta de design


Código fonte do Github: Prova de conceito


Links úteis


Artigo "ShowDialog personalizado"
Descrição escassa da classe DispatcherFrame usando tradução automática
A espera pela conclusão via aguardar é fornecida neste artigo.

Source: https://habr.com/ru/post/pt452268/


All Articles