问题 关闭后处理表格


我在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("");
    }
}

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


12571
2017-08-31 14:47


起源

为什么要在垃圾收集器为您执行此操作之前处理表单(假设没有对表单的引用)? - Lazarus
什么“它不起作用”是什么意思?提出了例外吗?窗户不会消失吗? @Lazarus:好问题。 - DHN
表格关闭后是否需要处理表格? - Reza Aghaei


答案:


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

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

  1. 你有一个全局的Timer实例
  2. 你创建form2
  3. Form2订阅计时器
  4. Form2已关闭和/或处置
  5. Timer事件触发,递增计数器并显示MessageBox
  6. Timer事件会持续触发,直到App关闭。

要理解的要点是,Close / Dispose只改变Form的状态,他们不会(不能)'删除'实例。所以(封闭的)形式在那里,计数器字段仍在那里并且事件触发。


好的,第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;

8
2017-08-31 14:54



+1对于建议使用声明,可能想给他一个例子。 - jsmith
亲爱的Henk Holterman,删除计时器刻度事件是一个很好的解决方案,但我的问题是,为什么消息框显示表单何时处理? - Mironline
@Mironline:为什么不应该呢? Timer和MessageBox都不需要这种形式。尝试在timer_Tick中设置Control属性,您将遇到异常。 - Henk Holterman


最简单,最可靠的处理方式 Form 使用之后是将用法放在使用块内

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

C#中的using块是一个构造,它基本上将上述内容扩展为以下代码。

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

4
2017-08-31 15:04



在几秒块内,form2必须在访问之前初始化。如果它初始化,则永远不等于null。我试过了,但是消息框显示5秒后。 - Mironline
这仅适用于模态形式 - Dave Cousineau


这是一个古老的问题,但它涉及一些关于对象如何工作的有趣点。表格本质上是一个对象。同一类的所有对象共享相同的方法,但每个对象都有自己的数据。这是什么意思?这意味着,关闭或处置对象不会释放/删除/删除任何对象  从记忆中。只有数据。所有这些都是关于一般的对象,无论语言如何。

现在,特别是关于你的代码。让我们来看看这条线 Program.timer.Tick += timer_Tick; 确实。这给出了一个指向你的函数的指针 表单对象 到了 计时器对象。那么,现在,不管你做了什么 表单对象计时器对象 将继续调用该功能。计时器对象 不关心你的表单,甚至不知道Form对象的存在。它只关心 您传递指针的函数。就计时器对象而言,此功能是一个独立的功能。

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

不用说(或者可能不是那么不必要)如果关闭/处理表单从内存中清除了函数,那么计时器对象会有一个无效的指针,你的程序会 紧急 5秒后。


3
2017-11-02 07:53





也许我正在读错的问题,但我认为先生需要知道,要关闭一个以Form2.ShowDialog()打开的表单(比如form2),你需要在Form2中设置Form2.DialogResult。只需设置该成员即可关闭表单并返回结果。


1
2017-10-22 09:25





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

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


0
2017-08-31 15:23