gpt4 book ai didi

c# - 如果表单应用程序关闭 C#,如何防止发生 Timer Elapsed 事件

转载 作者:太空狗 更新时间:2023-10-30 01:34:34 25 4
gpt4 key购买 nike

我在 Windows 窗体应用程序 (Visual C#) 中有一个计时器,当我想退出该应用程序时它会导致问题。

计时器被定义为表单类的成员:

 partial class Form1 
{
//These are the members in question:
internal ComACRServerLib.Channel channel;
private System.Timers.Timer updateStuff;
}

计时器在表单应用程序的构造函数中声明/构造:

public Form1()
{
InitializeComponent();
updateStuff = new System.Timers.Timer();
updateStuff.Elapsed += new System.Timers.ElapsedEventHandler(updateStuff_Elapsed);
}

按下按钮即可启动和配置计时器:

 private void btnAcquire_Click(object sender, EventArgs e)
{
updateStuff.Interval = 100;
updateStuff.Enabled = true;
updateStuff.AutoReset = true;
updateStuff.Start();
}

当计时器到时,它会调用 updateStuff_Elapsed,它会通过 setText 获取要显示的信息(有一些代码可以确保调用 setText 是线程安全的)。

 private void updateStuff_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (!channel.isOffline)
{
object[] status = channel.GetACRCustom("P6144");
setText(System.Convert.ToString(status[0]));
}
}

public delegate void setTextDelegate(string text);

public void setText(string text)
{
if (this.lblTest.InvokeRequired == true)
{
setTextDelegate d = new setTextDelegate(setText);
this.Invoke(d, new object[] { text });
}
else
{
lblTest.Text = text;
}
}

在应用程序退出时,我尝试通过以下方式摆脱计时器并防止它再次触发:

protected override void Dispose(bool disposing)
{

if (disposing && (components != null))
{
updateStuff.AutoReset = false;
updateStuff.Stop();
updateStuff.Close();
updateStuff.Dispose();

components.Dispose();
}
base.Dispose(disposing);
}

但是如果计时器自动运行并且我退出程序,我总是会收到错误消息,即 Timer Elapsed 事件 updateStuff_elapsed 调用的例程正在尝试使用已经释放的资源!尽管我已经尽力在处理发生之前停止并销毁计时器。

如何在应用程序关闭时阻止计时器触发?

编辑

我尝试移动 Dispose 代码以尝试强制关闭计时器,但没有成功。我还尝试使用 updateStuff.Elapsed -= updateStuff_Elapsed 在停止和处理之前删除事件调用;

protected override void Dispose(bool disposing)
{
//now this code HAS to run always.
updateStuff.Elapsed -= updateStuff_Elapsed;
updateStuff.AutoReset = false;
updateStuff.Stop();
updateStuff.Close();
updateStuff.Dispose();

if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}

最佳答案

System.Timers.Timer 的文档中所述, Timer 的事件处理程序调用在 ThreadPool 线程上排队。因此,您必须假设事件处理程序可以一次调用多次,或者可以在禁用 Timer 后调用。因此,事件处理程序的设计必须能够正确处理这些情况。

首先,设置SynchronizingObject定时器的属性到窗体的实例。这会将事件处理程序的所有调用编码到 UI 线程,因此我们不需要为锁定表单字段而烦恼(我们将始终从同一个 UI 线程访问所有内容)。有了这个属性集,你也不需要在 setText 方法中调用 this.Invoke(...)。

public Form1()
{
updateStuff = new System.Timers.Timer();
updateStuff.SynchronizingObject = this;
...
}

public void setText(string text)
{
lblTest.Text = text;
}

然后创建标志,让您知道计时器是否已处理。然后只需在事件处理程序中检查此标志:

partial class Form1 
{
private bool Disposed;
....
}

protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
updateStuff.Dispose();
Disposed = true;
}

base.Dispose(disposing);
}

private void updateStuff_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if(!Disposed)
{
if (!channel.isOffline)
{
object[] status = channel.GetACRCustom("P6144");
setText(System.Convert.ToString(status[0]));
}
}
}

关于c# - 如果表单应用程序关闭 C#,如何防止发生 Timer Elapsed 事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30224717/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com