这篇是 的简化版,区别就是之前的自定义 MessageBox
控件是整个 app 中所有页面共享的,下面的简化版 MessageBox 只是应用于 MainPage 页面中,“询问
用户是否退出”的自定义弹出框。
在应用或游戏程序中,经常的一个场景就是在用户点击 Back 键时,应用询问用户是否退出,通常是重写
Page 页面的事件:
protected override async void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
但是,当弹出 MessageBox 10秒钟用户没有响应,应用则会退出,其实并不是 MessageBox 的 Bug,只要阻塞
OnBackKeyPress() 方法超过 10秒 ,应用都会退出的,如果先调用 e.Cancle = true 取消导航,再询问用户
是否退出,就不会出现这个问题。如果用户点击“确定”,则调用 App.Current.Terminate(); 结束当前应用进程。
一种简单的方式是:
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e) { e.Cancel = true; this.Dispatcher.BeginInvoke(delegate { if (MessageBox.Show("确定退出?", "提示", MessageBoxButton.OKCancel) == MessageBoxResult.OK) { App.Current.Terminate(); } }); base.OnBackKeyPress(e); }
另一种方式:
为了解决这个问题,方式之一就是自定义一个 MessageBox 控件:
页面的交互如下图:
第一步:自定义一个名为 MyDialog 的用户控件,页面的主要 xaml:
public partial class MyDialog : UserControl { public MyDialog() { InitializeComponent(); gridDialog.Visibility = System.Windows.Visibility.Collapsed; // 把第一个实例赋值给全局静态对象 if (_instance == null) _instance = this; } //用来控制异步线程中 弹出框 结果返回的时机 private static AutoResetEvent myResetEvent = new AutoResetEvent(false); static MessageBoxResult messageBoxResult; //用一个单一实例,使得应用中的所有页面使用同一个实例 static MyDialog _instance; static MyDialog Instance { get { //if (_instance == null) // _instance = new MyDialog(); return _instance; } } ////// 显示包含指定文本、标题栏标题和响应按钮的消息框 /// /// 要显示的消息 /// 消息框的标题 /// 一个值,用于指示要显示哪个按钮或哪些按钮 ///一个值,用于指示用户对消息的响应 public static TaskShow(string messageBoxText, string caption, MessageBoxButton button) { return Task .Factory.StartNew(() => { Instance.Dispatcher.BeginInvoke(delegate { Instance.gridDialog.Visibility = Visibility.Visible; Instance.contentContainer.Content = messageBoxText; Instance.txtTitle.Text = caption; if (button == MessageBoxButton.OKCancel) { Instance.btnCancle.Visibility = Visibility.Visible; } else { Instance.btnCancle.Visibility = Visibility.Collapsed; } //Instance.UpdateLayout(); Instance.ShowMessageBoxSB.Stop(); Instance.ShowMessageBoxSB.Begin(); }); myResetEvent.WaitOne(); return messageBoxResult; }); } private void btnOk_Click(object sender, RoutedEventArgs e) { txtTitle.Text = ""; contentContainer.Content = null; gridDialog.Visibility = System.Windows.Visibility.Collapsed; messageBoxResult = MessageBoxResult.OK; // 使异步线程的 Show() 方法继续执行 myResetEvent.Set(); } private void btnCancle_Click(object sender, RoutedEventArgs e) { txtTitle.Text = ""; contentContainer.Content = null; gridDialog.Visibility = System.Windows.Visibility.Collapsed; messageBoxResult = MessageBoxResult.Cancel; myResetEvent.Set(); } // 用来控制当弹出框显示的时候,如果用户点击 Back 按键,则隐藏弹出框, // 在 App.xaml.cs 中的 RootFrame_Navigating 事件中调用 public static bool DialogIsOpen { get { if (Instance != null && Instance.gridDialog.Visibility == Visibility.Visible) { Instance.btnCancle_Click(null, null); return true; } else { return false; } } } }
第二步:在 MainPage.xaml 页面中,添加如下代码:
protected override async void OnBackKeyPress(System.ComponentModel.CancelEventArgs e) { // 首先取消默认 Back 键关闭应用 e.Cancel = true; // 如果 MainPage 页面中,弹出了其它的弹出框,关闭它, // 在 DialogIsOpen 属性中实现 if (MyDialog.DialogIsOpen) { //可以做其它事情 } else { if (MessageBoxResult.OK == await MyDialog.Show("确定要退出吗?", "温馨提示:", MessageBoxButton.OKCancel)) { // 终止当前应用程序。该方法是在 WP8 中加入的,WP7 中木有 App.Current.Terminate(); } } base.OnBackKeyPress(e); }