C#WPF模拟Window.ShowDialog()或处理DispatcherFrame

问题陈述


作为开发一个应用程序的一部分,需要实施以下方案:


  1. 异步方法请求数据
  2. 用户从键盘输入数据
  3. 该方法接收输入结果作为函数的结果,并从同一位置继续

附加要求:不要创建其他窗口。


看起来很简单吗? 原来真的很简单。 但是首先是第一件事。


解决方案


首次尝试而不进行互联网搜索的尝试导致主线程被阻塞,因此没有任何好处。 在碰到一篇文章时 ,我正要使用ShowDialog。 作者研究了如何在WPF中制作ShowDialog。 你需要什么!


在他的文章中,他建议创建自己的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); } 

我不需要窗口锁定,因为所有内容都显示在一个窗口中,并且还需要返回值。 我们删除了太多,添加了正确的...


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

Dispatcher.PushFrame(frame)阻止GetInput()方法GetInput()直到frame.Continue变为false为止。 当开始新的帧时,主循环暂停并且开始新的帧。 该循环处理系统消息,而主循环中的执行点不再移动。 当我们退出当前帧( frame.Continue = false )时,主循环将从同一位置继续工作。


现在只剩下检查性能了。


在MainWindow中,创建一个按钮并在其上挂起一个处理程序,这将启动任务,在该任务中,我们将转向键盘输入。


处理程序代码:


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

我使用此解决方案输入了验证码和用于双重身份验证的其他代码。 但是可能会有大量的应用程序。


! 该示例代码包含违反mvvm原理的行为,并且 不要用力 缺少设计


Github源代码: 概念验证


有用的链接


文章“自定义ShowDialog”
使用机器翻译的DispatcherFrame类的简短描述
本文提供了通过等待来等待完成

Source: https://habr.com/ru/post/zh-CN452268/


All Articles