我有这段代码:
private void Form1_Load(object sender, EventArgs e)
{
/*start update timer*/
System.Timers.Timer updateticker = new System.Timers.Timer();
updateticker.Elapsed += new ElapsedEventHandler(update_overload);
//10 minute ticker
updateticker.Interval = 600000;
//30 sec ticker
updateticker.Interval = 30000;
updateticker.Enabled = true;
System.Timers.Timer guiTimer = new System.Timers.Timer();
guiTimer.Elapsed += new ElapsedEventHandler(idle_display);
//1 minute ticker
guiTimer.Interval = 60000;
//30 sec ticker
//updateticker.Interval = 30000;
guiTimer.Enabled = true;
}
//run front end idle timer
public void idle_display(object source, ElapsedEventArgs e)
{
if (minutes_left > 0) {
minutes_left = minutes_left - 1;
}
lbl_dyn_status.Text = "Time until next automatic update: "+ minutes_left + " minutes.";
}
Visual Studio将第二个函数的最后一行标记为不安全的交叉线程。任何人都可以建议我如何重写这个以解决问题?
干杯
答案 0 :(得分:4)
使用System.Windows.Forms.Timer
代替System.Timers.Timer
或使用Timer的SynchronizingObject属性。
当SynchronizingObject为null时,将在系统线程池的线程上调用处理Elapsed事件的方法。有关系统线程池的更多信息,请参阅ThreadPool。
当Elapsed事件由可视化Windows窗体组件(如按钮)处理时,通过系统线程池访问组件可能会导致异常或者可能无法正常工作。通过将SynchronizingObject设置为Windows窗体组件来避免此影响,这会导致处理Elapsed事件的方法在创建组件的同一线程上调用。
答案 1 :(得分:2)
正如其他人所建议的那样,使用System.Windows.Forms.Timer
。与在线程池线程上运行的System.Threading.Timer
不同,它保证在UI线程上调用tick事件。
UI线程是唯一允许修改UI的线程。这就是您尝试编写lbl_dyn_status.Text
时遇到异常的原因。
答案 2 :(得分:1)
使用System.Windows.Forms.Timer计时器而不是System.Timers.Timer。
答案 3 :(得分:0)
将处理程序更改为
public void IdleDisplay(object source, ElapsedEventArgs e)
{
if (lbl_dyn_status.InvokeRequired)
{
this.Invoke(IdleDisplay)
}
else
{
if (minutes_left > 0)
{
minutes_left = minutes_left - 1;
}
lbl_dyn_status.Text = string.Format(
"Time until next automatic update: {0} minutes.",
minutes_left);
}
}
这种方式允许您使用无线程System.Threading.Timer
,但检查处理程序中的跨线程调用。如果检测到,则通过Form
类在主GUI线程上调用该调用。
这是on MSDN in more detail here.
所描述的更一般地说,你不应该使用计时器来计算这样的时间。您的计时器绑定的线程越多,它就越可能与实际经过的时间不同。您可以使用计时器来安排时钟更新,但是,您应该计算自某个固定点以来的经过时间,而不是使用迭代计数器。