• [WPF]如何在关闭非模态子窗体时用消息框确认——解决最小化窗体时抛出的异常


    又是一个看起来很简单的问题。像下面这样在Closing里弹出个MessageBox确认一下不就行了?

     

    public static void OnWindowClosing(object sender, CancelEventArgs e)
    {
        
    if (MessageBox.Show(string.Format("Are you sure to close the {0}?", (sender as Window).Title),
           
    "Confirm", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No) == MessageBoxResult.No)
        
    {
            e.Cancel 
    = true;
        }

    }

    代码简单得不能再简单了,而且试了一下可以达到目的,似乎是没有什么问题啊。但是很多代码需要大量的测试才能发现问题。这个代码就是其中之一。

     

    在说明BUG之前,先给几个信息,大家可以猜猜如何重现这个问题。

    1.       只有非模态的子窗体有这个BUG。主窗口是没有问题的。

    2.       弹出MessageBox的时候,UI消息处理线程会被阻塞。

    3.       抛出的异常,是InvalidOperationException

    4.       子窗体与主窗体有从属关系,主窗体最小化时,子窗体也跟着最小化。

    5.       最后一个信息,已经是把BUG告诉大家了。就是Error Message,如下图所示。

    1. Exception信息

     

    看了Error Message,应该都明白了。主窗体没有问题,因为关主窗体时弹出消息框之后,根本没有什么UI操作可以最小化主窗体。(自己写另一个程序去最小化这个窗体不在考虑范围之内。)所以不会有这个BUG,但是为什么子窗体有呢。

     

    下面描述一个这个Bug的产生过程。

    1.       主窗体和子窗体都显示出来。

    2.       点击关闭按钮关闭子窗体,此时会弹出消息框问要不要关。不去理这个消息框。

    3.       点击任务栏上的主窗体,使主窗体最小化。这里子窗体也最小化了。

    4.       再点任务栏上的主窗体,使主窗体还原。异常抛出。而且,即使handle了这个异常,这个子窗体也会变黑的。

     

    可以发现,其实罪魁祸首是上面的第4条信息。操作系统在主窗体最小化时,自动最小化其子窗体,结果帮了倒忙。这种自动做事帮倒忙的事情应该还有不少。还发现过的一例就是在WPF Bug清单里的RadioButton无法绑定的BUG,也是系统自动做事造成的。但是逻辑上来讲,这么做也的确是对的。

     

    最后想办法解决问题的,只能是我们自己。ExceptionMessage上说在窗体Closing的时候,不能做这做那,但是我们又要做,那怎么办呢?其实是我们的MessageBox阻塞了窗体Close的过程才有这个异常。那么解决方案就出来,让MessageBox不阻塞UI线程不就得了。代码如下

     

    public static void OnWindowClosingAdv(object sender, CancelEventArgs e)
    {
        
    Prevent Recursion

        e.Cancel 
    = true//Cancel every close at once.

        Window window 
    = sender as Window;
        window.Dispatcher.BeginInvoke(
    new Action<Window>(ConfirmClose), window);
    }


    private static void ConfirmClose(Window window)
    {
        
    if (MessageBox.Show(string.Format("Are you sure to close the {0}?", window.Title),
            
    "Confirm", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No) == MessageBoxResult.Yes)
        
    {
            window.Close();
        }

    }

     

    注:其中的Prevent Recursion代码段是为了防止递归调用的。完全可以用一个临时变量代码代替,而且不会出现硬编码的字符串。分析调用栈只是为了突出代码相对于原版的丑恶。^_^

     

    这次还好,为了Fix系统的逻辑BUG,并没有多写多少代码。

     

     

     

     

  • 相关阅读:
    Codeforces Round #602 (Div. 2, based on Technocup 2020 Elimination Round 3)
    Educational Codeforces Round 79 (Rated for Div. 2)
    Codeforces Global Round 6
    Codeforces Round #608 (Div. 2)
    Codeforces Round #606 (Div. 2)
    Codeforces Round #603 (Div. 2)
    Educational Codeforces Round 77 (Rated for Div. 2)
    洛谷 P3805 【模板】manacher算法
    HDU 1671 Phone List [字典树]
    2019牛客暑期多校训练营(第一场)E.ABBA
  • 原文地址:https://www.cnblogs.com/nankezhishi/p/1375945.html
Copyright © 2020-2023  润新知