覆盖Windows窗体中的标准关闭(X)按钮


75

如何更改用户单击Windows Forms应用程序(在C#中)的关闭(红色X)按钮时发生的情况?

Answers:


136

您可以重写OnFormClosing来执行此操作。请注意,不要做任何意外的事情,因为单击“ X”关闭是一种众所周知的行为。

protected override void OnFormClosing(FormClosingEventArgs e)
{
    base.OnFormClosing(e);

    if (e.CloseReason == CloseReason.WindowsShutDown) return;

    // Confirm user wants to close
    switch (MessageBox.Show(this, "Are you sure you want to close?", "Closing", MessageBoxButtons.YesNo))
    {
    case DialogResult.No:
        e.Cancel = true;
        break;
    default:
        break;
    }        
}

3
我的猜测是他想尽量减少拖累工作,但是您要从我这里得到+1,请注意。
山姆·哈威尔2009年

4
@Jon B-您应检查关闭原因。如果Windows关闭,则不想显示消息框。
菲利普·华莱士

1
我做了一个转换声明,所以我不必滚动到右侧就可以看到==
Sam Harwell

2
@Philip:嗯,这取决于。每次相关(有更改)时,均应显示一个“您要保存”框,取消该框应取消关机。例如,VS就是这种情况。应该显示一个烦人的“您要关闭吗” ...理想情况下,永远不要显示,但是如果按照这种方式,则应在关机时绕过它。
R. Martinho Fernandes,2009年

@Phillip-这是真的推荐吗?我相信大多数应用程序都会询问您是否要将更改保存到修改后的文件中,而不论关闭原因为何。
Groo


18

这些答案缺乏一件事,而哪些新手可能正在寻找,那就是尽管有一个活动很高兴:

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    // do something
}

除非您注册该事件,否则它什么也不会做。将其放在类构造函数中:

this.FormClosing += Form1_FormClosing;

10

覆盖OnFormClosing或注册事件FormClosing

这是一个以派生形式重写OnFormClosing函数的示例:

protected override void OnFormClosing(FormClosingEventArgs e)
{
   e.Cancel = true;
}

这是事件处理程序的一个示例,该事件处理程序可以阻止窗体关闭,该窗体可以在任何类中:

private void FormClosing(object sender,FormClosingEventArgs e)
{  
   e.Cancel = true;
}

要获得更高级的信息,请检查FormClosingEventArgs的CloseReason属性,以确保执行了适当的操作。您可能只想在用户尝试关闭表单时执行其他操作。


8

正如Jon B所说,但您还需要检查ApplicationExitCallTaskManagerClosingCloseReason:

protected override void OnFormClosing(FormClosingEventArgs e)
{
    if (  e.CloseReason == CloseReason.WindowsShutDown 
        ||e.CloseReason == CloseReason.ApplicationExitCall
        ||e.CloseReason == CloseReason.TaskManagerClosing) { 
       return; 
    }
    e.Cancel = true;
    //assuming you want the close-button to only hide the form, 
    //and are overriding the form's OnFormClosing method:
    this.Hide();
}


3

当您使用作为MDI容器的Form时,能够处理x按钮click事件非常有用的一种情况。原因是关闭和关闭事件首先由孩子提出,最后由父母提出。因此,在一种情况下,用户单击x按钮以关闭应用程序,并且MDI父级要求进行确认。万一他决定不关闭应用程序,而是继续进行他正在做的事情,那么孩子们将已经处理了关闭事件,可能丢失任何信息/工作。一种解决方案是从Windows消息循环中以您的主应用程序形式拦截WM_CLOSE消息(即已关闭,终止该应用程序),如下所示:

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 0x0010) // WM_CLOSE
        {
            // If we don't want to close this window 
            if (ShowConfirmation("Are you sure?") != DialogResult.Yes) return;
        }

        base.WndProc(ref m);
    }

1

这是一个很常见的问题。一个很好的答案是在这里:

用户单击X时VB.NET重载默认功能(关闭程序)


如果您不满意将代码放入Form_Closing事件中,那么我知道的唯一其他选择是我使用过一两次的“ hack”。不必求助于这种hack,但是这里是:


不要使用正常的关闭按钮。而是,创建您的窗体,以便它没有ControlBox。您可以通过在表单上设置ControlBox = false来执行此操作,在这种情况下,表单顶部仍将显示普通栏,或者您可以将表单的FormBorderStyle设置为“无”。将不会在顶部或任何其他可见的边框上出现横条,因此您必须通过在窗体上绘图或通过艺术使用Panel控件来模拟它们。

然后,您可以添加一个标准按钮,使其看起来像关闭按钮,然后在其中放置清理代码。在按钮事件结束时,只需调用this.Close()(C#)或Me.Close()(VB)


为什么有人不喜欢处理结束活动?恕我直言,添加一个自定义(但令人信服的)“关闭”按钮并不是一件容易的事(特别是当您考虑到过渡效果和Aero东西时,通常不会感到任何痛苦)。
Groo

在我链接的答案中,提出问题的人出于某种原因不想使用Form_Closing事件。我不确定他的原因是什么,但他不想使用它。在使用hack的时候,我只是想要一个外观不同的关闭按钮。
David

换句话说,另一个答案既链接到(足够公平)又被复制粘贴,这就是为什么答案一半不相关而其余答案建议此处没有任何理由的原因。
jwg

0

接受的答案效果很好。我使用的另一种方法是为主窗体创建一个FormClosing方法。这与覆盖非常相似。我的示例是针对一个应用程序,该应用程序在单击“表单”上的“关闭”按钮时会最小化到系统托盘。

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        if (e.CloseReason == CloseReason.ApplicationExitCall)
        {
            return;
        }
        else
        {
            e.Cancel = true;
            WindowState = FormWindowState.Minimized;
        }            
    }

这将允许ALT + F4或应用程序中调用Application.Exit()的任何内容在单击(X)时正常工作将使应用程序最小化。


-1
protected override bool ProcessCmdKey(ref Message msg, Keys dataKey)
    {
        if (dataKey == Keys.Escape)
        {
            this.Close();
            //this.Visible = false;
            //Plus clear values from form, if Visible false.
        }
        return base.ProcessCmdKey(ref msg, dataKey);
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.