我试图理解为什么Windows.Forms.Timer
在创建form
时没有被处理掉。我有这个简单的形式:
public partial class Form1 : Form {
private System.Windows.Forms.Timer timer;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
timer = new Timer();
timer.Interval = 1000;
timer.Tick += new EventHandler(OnTimer);
timer.Enabled = true;
}
private void OnTimer(Object source, EventArgs e) {
Debug.WriteLine("OnTimer entered");
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e) {
this.Dispose();
}
}
当我关闭它时,会调用this.Dispose
,但会继续调用计时器触发事件。我认为Dispose
释放了被处置对象拥有的所有对象。这是不真实的吗? Timer
是否有特定行为?
现在,我发现处理计时器的方法是timer.Tick -= OnTimer;
- 我在Form1_FormClosed
事件中调用它。这是一个好的解决方案,还是我应该这样做?
或者只是做得更好:
private void Form1_FormClosed(object sender, FormClosedEventArgs e) {
timer.Dispose();
this.Dispose();
}
答案 0 :(得分:12)
正如我在之前的评论中告诉你的,你应该尝试:
private Form1_FormClosing(...)
{
timer.Stop();
timer.Tick -= new EventHandler(OnTimer);
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
timer.Dispose();
timer = null;
}
这很好,因为你阻止计时器再次循环(在FormClosing中)你可以检查其他部分(在这个例子中是非因为你关闭了表单,但是作为例子),如果该对象(计时器)已经< em>删除然后再使用它 所以在其他部分你可以做到
if (timer != null) // Note: this is false if you just use timer.Dispose()
{
....
}
答案 1 :(得分:4)
处理IDisposable
类的可支配成员的唯一正确方法是在Dispose(bool disposing)
方法中执行此操作(查看MSDN文章)。换句话说,您可以打开自动生成的Form.Designer.cs
文件并将其放入正确的方法中。
另一方面,如果您通过VS Designer添加Timer
(而不是自己实例化),它将被添加到components
容器中:
// autogenerated inside Form.Designer.cs, InitializeComponent() method
this.timer = new System.Windows.Forms.Timer(this.components);
然后在components
成员被处置时妥善处理:
// autogenerated inside Form.Designer.cs, Dispose(bool disposing) method
if (disposing && (components != null))
{
components.Dispose();
}
如果您想自己这样做,请记住,如果设计师不认为需要,则不会实例化components
。因此,components
可能是null
。
解决此问题的最简单方法:通过从工具箱中拖动计时器来添加计时器,然后在Form_Load
处理程序中启动它。
答案 2 :(得分:1)
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{ timer.Stop(); }
我不应该把这个.Dispose();在表单关闭事件中只是停止计时器。
答案 3 :(得分:1)
EventHandler是持久引用,删除引用并在Closing事件上停止计时器,或者在不需要时立即停止。如果要检查定时器是否处理,请在已关闭的事件
中进行检查答案 4 :(得分:1)
简单Timer.Dispose()
删除计时器资源,包括将来停止计时器。
但是,有可能在Dispose()
返回后,有一些回调要么正在执行,要么就位于线程池的工作队列中等待执行。
一旦计时器的所有回调都完成,第二次重载Timer.Dispose(WaitHandle)
将发出传入的对象信号。这可以是任何WaitHandle
,例如ManualResetEvent
。
为了简化操作,您可以传入WaitHandle.InvalidHandle
,Timer.Dispose()
只有在所有回调都完成后才会返回。这避免了必须分配一个真正的事件对象,通常是你想要做的。
由于WaitHandle
是抽象的,你需要使用一点hack,即创建自己的子类。
class InvalidWaitHandle : WaitHandle {}
Timer tmr = new Timer(...);
tmr.Dispose(new InvalidWaitHandle);