wpf 如何在关闭处理程序中区分“单击窗口关闭按钮(X)”与 window.Close()

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13361260/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 06:10:55  来源:igfitidea点击:

How to distinguish 'Window close button clicked (X)' vs. window.Close() in closing handler

wpfwindow

提问by mola

Is there a clever way to detect whether a window was closed by

有没有一种聪明的方法来检测窗口是否被关闭

  • A user pressing the (X) button in the upper right corner of the window or
  • window.Close() has been called programatically.
  • 用户按下窗口右上角的 (X) 按钮或
  • window.Close() 已被以编程方式调用。

I would like to detect this in the window.Closing handler. I could set a flag whenever I call window.Close(), but this is not a very pretty solution.

我想在 window.Closing 处理程序中检测到这一点。我可以在每次调用 window.Close() 时设置一个标志,但这不是一个很好的解决方案。

回答by Andy

I'm not sure I like this at all but it's a question that you obviously have a reason for asking. if you were to take a stack trace in the OnClosing event you could look up for the Window.Close event.

我不确定我是否喜欢这个问题,但您显然有理由提出这个问题。如果您要在 OnClosing 事件中进行堆栈跟踪,您可以查找 Window.Close 事件。

protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
   bool wasCodeClosed = new StackTrace().GetFrames().FirstOrDefault(x => x.GetMethod() == typeof(Window).GetMethod("Close")) != null;
   if (wasCodeClosed)
   {
       // Closed with this.Close()
   }
   else
   {
       // Closed some other way.
   }

   base.OnClosing(e);
}

回答by norekhov

The difference is the following:

区别如下:

Window.Close() causes WM_CLOSE to be send to window.

Window.Close() 导致 WM_CLOSE 被发送到窗口。

Alt+F4 and X button causes WM_SYSCOMMAND message with SC_CLOSE type. You can decide if you wish to route this message further ( and cause WM_CLOSE in the end ).

Alt+F4 和 X 按钮会产生 SC_CLOSE 类型的 WM_SYSCOMMAND 消息。您可以决定是否希望进一步路由此消息(并最终导致 WM_CLOSE)。

Here's a piece of code to catch this message. Return "True" from delegate if you wish to cancel default behaviour:

这是捕获此消息的一段代码。如果您希望取消默认行为,请从委托返回“True”:

class SystemMenu : IDisposable
{
    const int WM_SYSCOMMAND = 0x0112;
    const int SC_CLOSE = 0xF060;

    public delegate bool HandleSystemCommand();
    HwndSource _source;
    HandleSystemCommand _handler;

    public SystemMenu(Window window, HandleSystemCommand handler )
    {
        _handler = handler;
        _source  = HwndSource.FromHwnd(new WindowInteropHelper( window ).Handle);
        _source.AddHook(WndProc);
    }

    public void Dispose() {
        _source.RemoveHook(WndProc);
    }

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        switch (msg)
        {
            case WM_SYSCOMMAND:
                int command = wParam.ToInt32() & 0xfff0;
                if (command == SC_CLOSE)
                    handled = _handler();
                break;
            default:
                break;
        }
        return IntPtr.Zero;
    }
}