2010-08-31 83 views
11

我在C#中遇到了打开和关闭窗体的新问题。关闭后处理表格

我的问题是如何处理关闭后的窗体。

这里是我的代码:

的Program.cs:

static class Program 
{ 
    public static Timer timer; 

    [STAThread] 
    static void Main() 
    { 
     Application.EnableVisualStyles(); 
     Application.SetCompatibleTextRenderingDefault(false); 

     timer = new Timer { Interval = 1000}; 
     timer.Start(); 

     Application.Run(new Form1()); 
    } 
} 

Form1.cs中:

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     Form2 form = new Form2(); 
     form.ShowDialog(); 
     /// I've tried Dispose() method . but didn't work 
    } 
} 

Form2.cs:

public partial class Form2 : Form 
{ 
    public Form2() 
    { 
     InitializeComponent(); 
    } 

    private void Form2_Load(object sender, EventArgs e) 
    { 
     Program.timer.Tick += timer_Tick;  
     Close(); 
     // I've tried Dispose() method instead of Close() but didn't work 
    } 

    private int count = 0; 
    void timer_Tick(object sender, EventArgs e) 
    { 
     count++; 
     if (count == 5) MessageBox.Show(""); 
    } 
} 

编辑: 我的问题是:为什么消息框在5秒后显示form2已关闭!

+1

为什么你想在垃圾收集器为你做这件事之前处理这些表单?(假设没有对表单的引用)? – Lazarus 2010-08-31 14:52:09

+2

“它没有工作”是什么意思?是否引发异常?窗口不会消失吗? @拉扎罗斯:好问题。 – DHN 2010-08-31 14:53:05

+0

[我需要在表单关闭后处理表单吗?](https://stackoverflow.com/a/39501121/3110834) – 2017-12-04 19:03:44

回答

8

编辑:这个问题原来是关于处置。

首先,Dispose已经注意到垃圾收集。会发生以下情况:

  1. 你有一个全球性的Timer实例
  2. 创建窗口2
  3. 窗体2订阅计时器
  4. 窗体2被关闭和/或设置
  5. 计时器事件触发时,递增计数器并显示一个MessageBox
  6. Timer事件一直发射,直到App关闭。

要理解的要点是关闭/处置只会改变窗体的状态,他们不会(不能)'删除'实例。所以(闭合)形式在那里,反场仍然存在,事件发生。


OK,第1部分:

一个using() {}块会更好,但这应该工作:

private void button1_Click(object sender, EventArgs e) 
    { 
     Form2 form = new Form2(); 
     form.ShowDialog(); 
     /// I've tried Dispose() method . but didn't work 
     form.Dispose(); // should work 
    } 

如果不是,请说明 “不工作”。


private void Form2_Load(object sender, EventArgs e) 
    { 
     Program.timer.Tick += timer_Tick;  
     Close(); 
     /// I've tried Dispose() method instead of Close() . but didn't work 
    } 

这是很奇怪,但我会认为这是问题的人工代码。

您的全球Program.Timer现在存储对您的Form2实例的引用,并保持它不被收集。它不会阻止它被丢弃/关闭,所以你的计时器将继续为封闭形式开火,这通常会失败并导致其他问题。

  1. 不这样做(给Form2的它自己的定时器)
  2. 使用FormClosed事件退订:Program.timer.Tick -= timer_Tick;
+2

+1对于建议使用语句,可能想给他一个例子。 – jsmith 2010-08-31 14:56:23

+0

亲爱的亨克霍尔特曼,删除计时器滴答事件是很好的解决方案,但我的问题是,为什么消息框显示时,表单已处置? – Mironline 2010-08-31 15:10:28

+1

@Mironline:为什么不呢? Timer和MessageBox都不需要这种形式。尝试在timer_Tick中设置一个Control属性,你将会有一个异常。 – 2010-08-31 15:18:12

4

最简单和最可靠的方法使用后处置废弃Form是把使用块内部的用法

using (Form2 form = new Form2()) { 
    form.ShowDialog(); 
} 

C#中的使用块是一种基本上将以上代码扩展到以下代码的构造。

Form2 form; 
try { 
    form = new Form2(); 
    ... 
} finally { 
    if (form != null) { 
    form.Dispose(); 
    } 
} 
+0

以秒为单位,form2必须在访问之前初始化。如果它初始化永远不等于null。我试过了,但消息框在5秒后显示。 – Mironline 2010-08-31 15:18:12

+0

这只适用于模态表单 – 2017-06-27 23:52:55

0

form.ShowDialog()将窗体显示为模态对话框。这意味着该呼叫在表单关闭之前不会返回。
请注意,单击模式对话框上的关闭X不会关闭表单,它只是隐藏它。我猜测这就是让你困惑的原因。 如果你想让form1中的代码继续执行而不是阻塞,你应该调用Show()而不是ShowDialog()。点击X时,非模态将关闭。

如果您确实需要阻塞模式对话框,则应该按照其他答案中所述使用使用块包围表单。
建立一个模式对话框时,通常会添加一个“OK”按钮或类似的对象,并将该表单的AcceptButton属性设置为该按钮,以允许用户按下Enter键关闭该表单。同样,您可以添加一个“取消”按钮并设置CancelButton属性来捕获Esc键。
向两个按钮添加点击处理程序,相应地设置表单的DialogResult属性并调用Close()。

1

也许我正在阅读的问题是错误的,但我想先生们需要知道,要关闭Form2.ShowDialog()打开的窗体(比如form2),您需要在Form2中设置Form2.DialogResult。只需设置该成员即可关闭表单并返回结果。

3

这是一个古老的问题,但它涉及到一些关于对象如何工作的有趣观点。表单本质上是一个对象。同一类的所有对象共享相同的方法,但每个对象都有自己的数据。这是什么意思?这意味着,关闭或处理对象不会从内存中释放/删除/删除任何代码。只有数据。所有关于一般物体的事情,不管语言如何。

现在,具体关于您的代码。让我们来看看Program.timer.Tick += timer_Tick;这行。这会在表单对象定时器对象中给出指向您的函数的指针。所以,现在,无论您对表单对象做什么,定时器对象都将继续调用该函数。计时器对象不关心您的表单,甚至不知道表单对象的存在。它只关心你传递给的指针的功能。就计时器对象而言,这个函数是一个独立的函数。

Form.Close()是做什么的? Form.Close()处理表单使用的资源,也就是标记表单的垃圾回收控件,除非表单使用ShowDialog显示。在这种情况下,必须手动调用Dispose()。MSDN

不用说(也许并非如此不必要的),如果关闭/处置的形式清除从记忆功能,定时器对象有一个无效的指针,你的程序会崩溃 5秒。