单击关闭按钮时隐藏窗体而不是关闭

当用户单击窗体上的 X按钮时,我如何隐藏它而不是关闭它?

我已经在 FormClosing中尝试了 this.hide(),但它仍然关闭了窗体。

63867 次浏览

来自 MSDN:

若要取消窗体的闭包,请将传递给事件处理程序的 FormClosingEventArgsCancel属性设置为 true

那就取消然后藏起来。

像这样:

private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
Hide();
}
}

(via Tim Huffman)

请注意,当这样做(几个答案已经张贴) ,您还需要找到一种方法,以允许用户关闭时,他们真的想要表单。如果用户试图在应用程序运行时关闭计算机,那么这确实会成为一个问题,因为(至少在某些操作系统上)这将阻止操作系统正确或有效地关闭计算机。

我解决这个问题的方法是检查堆栈跟踪——当用户试图单击 X时与系统试图结束应用程序以准备关闭时存在差异。

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
StackTrace trace = new StackTrace();
StackFrame frame;
bool bFoundExitCommand = false;
for (int i = 0; i < trace.FrameCount; i++)
{
frame = trace.GetFrame(i);
string methodName = frame.GetMethod().Name;
if (methodName == "miExit_Click")
{
bFoundExitCommand = true;
Log("FormClosing: Found Exit Command ({0}) - will allow exit", LogUtilityLevel.Debug3, methodName);
}
if (methodName == "PeekMessage")
{
bFoundExitCommand = true;
Log("FormClosing: Found System Shutdown ({0}) - will allow exit", LogUtilityLevel.Debug3, methodName);
}
Log("FormClosing: frame.GetMethod().Name = {0}", LogUtilityLevel.Debug4, methodName);
}
if (!bFoundExitCommand)
{
e.Cancel = true;
this.Visible = false;
}
else
{
this.Visible = false;
}
}

这是情态形式的行为。当您使用 form.ShowDialog()时,此行为就是 请求。原因就是这种形式。直到窗体被隐藏或销毁,ShowDialog 才会返回。因此,当形式是隐藏的,泵内的形式。ShowDialog 会销毁它,以便它可以返回。

如果要显示和隐藏窗体,则应使用 Modeless 对话框模型 Http://msdn.microsoft.com/en-us/library/39wcs2dh(vs.80).aspx

form.Show()立即返回,您可以显示和隐藏这个窗口所有您想要的,它将不会被销毁,直到您显式地销毁它。

当使用非模态表单的子表单时,还需要在循环中使用 Application.RunApplication.DoEvents运行消息泵。如果创建窗体的线程退出,则窗体将被销毁。如果线程不运行泵,那么它拥有的形式将无响应。

编辑: 这听起来像是 ApplicationContext设计用来解决的问题

基本上,从 ApplicationContext 派生一个类,将 ApplicationContext 的实例作为参数传递给 Application.Run()

// Create the MyApplicationContext, that derives from ApplicationContext,
// that manages when the application should exit.


MyApplicationContext context = new MyApplicationContext();


// Run the application with the specific context.
Application.Run(context);

应用程序上下文需要知道什么时候可以退出应用程序,什么时候表单被隐藏不应该退出应用程序。当应用程序退出时。应用程序上下文或窗体可以调用应用程序上下文的 ExitThread()方法来终止消息循环。这时 Application.Run()将返回。

如果不了解窗体的层次结构以及决定何时隐藏窗体和何时退出的规则,就不可能更具体。

我已经在之前的回答中做了评论,但是我认为我应该提供我自己的评论。基于你的问题,这段代码与上面的答案相似,但是增加了另一个提到的特性:

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
Hide();
}
}

如果用户只是单击窗口中的 X,则表单将隐藏; 如果任何其他操作,如 Task Manager、 Application.Exit()或 Windows 关闭,则表单将正确关闭,因为将执行 return语句。

如果你想使用 show/hide 方法,我最近做的一个游戏的菜单结构就是这么做的..:

为你自己创建一个按钮和你想要做的事情,例如一个“下一步”按钮和匹配下面的代码到你的程序。对于本例中的下一个按钮,代码如下:

btnNext.Enabled = true; //This enabled the button obviously
this.Hide(); //Here is where the hiding of the form will happen when the button is clicked
Form newForm = new newForm(); //This creates a new instance object for the new form
CurrentForm.Hide(); //This hides the current form where you placed the button.

下面是我在游戏中使用的代码片段,它可以帮助你理解我要解释的内容:

    private void btnInst_Click(object sender, EventArgs e)
{
btnInst.Enabled = true; //Enables the button to work
this.Hide(); // Hides the current form
Form Instructions = new Instructions(); //Instantiates a new instance form object
Instructions.Show(); //Shows the instance form created above
}

因此,有一个 show/hide 方法,只需要几行代码,而不是为这样一个简单的任务编写大量代码。 我希望这有助于解决你的问题。

根据其他回复,您可以将其放在表单代码中:

    protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
Hide();
}
}

根据 MSDN的说法,优先选择覆盖:

OnFormClose 方法还允许派生类处理 事件而不附加委托。这是首选技术 用于在派生类中处理事件。