关闭后处理表格
Posted
技术标签:
【中文标题】关闭后处理表格【英文标题】: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:好问题。 Do I need to Dispose a Form after the Form got Closed? 【参考方案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 与垃圾收集有关。会发生以下情况:
-
您有一个全局 Timer 实例
您创建 form2
Form2 订阅定时器
Form2 已关闭和/或处置
Timer 事件触发,计数器递增并显示 MessageBox
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 实例的引用,并将防止它被收集。它不会阻止它被处置/关闭,因此您的计时器将继续为已关闭的表单触发,这通常会失败并导致其他问题。
-
不要这样做(给 Form2 自己的计时器)
使用 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 秒后显示。以上是关于关闭后处理表格的主要内容,如果未能解决你的问题,请参考以下文章