【问题标题】:Dispose form after closing关闭后处理表格
【发布时间】:2011-04-06 07:49:38
【问题描述】:

我遇到了在 C# 中打开和关闭表单的新问题。

我的问题是关闭后如何处理表单。

这是我的代码:

程序.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秒后显示消息框!

【问题讨论】:

  • 为什么要在垃圾收集器为您执行此操作之前处理表单(假设没有对剩余表单的引用)?
  • “它不起作用”是什么意思?是否引发异常?窗口不会消失吗? @Lazarus:好问题。

标签: c# winforms forms dispose


【解决方案1】:

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

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

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

不用说(或者也许不是那么不必要)如果关闭/处理表单从内存中清除了函数,计时器对象将有一个无效的指针,并且您的程序将在 5 秒后崩溃 .

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      首先,Dispose 与垃圾收集有关。会发生以下情况:

      1. 您有一个全局 Timer 实例
      2. 您创建 form2
      3. Form2 订阅定时器
      4. Form2 已关闭和/或处置
      5. Timer 事件触发,计数器递增并显示 MessageBox
      6. Timer 事件一直触发,直到应用程序关闭。

      要理解的要点是 Close/Dispose 仅​​更改表单的状态,它们不会(不能)“删除”实例。所以(关闭的)表单在那里,计数器字段仍然在那里并且事件触发。


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

      【讨论】:

      • +1 建议使用using语句,不妨举个例子。
      • 亲爱的 Henk Holterman,删除计时器滴答事件是一个很好的解决方案,但我的问题是,为什么在表单处理完毕后会显示消息框?
      • @Mironline:为什么不应该呢? Timer 和 MessageBox 都不需要这种形式。尝试在 timer_Tick 中设置一个 Control 属性会出现异常。
      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

        使用后处理Form的最简单和最可靠的方法是将用法放在 using 块中

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

        C# 中的 using 块本质上是将上面的代码扩展为下面的代码。

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

        【讨论】:

        • 以秒为单位,form2 必须在访问之前进行初始化。如果它初始化永远不等于null。我试过了,但消息框会在 5 秒后显示。
        猜你喜欢
        • 1970-01-01
        • 2012-07-28
        • 1970-01-01
        • 2017-09-28
        • 1970-01-01
        • 2011-05-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多