我遇到了在backgroundworker的DoWork事件中更改计时器Interval的问题。通过单击按钮更改间隔时,计时器停止并且不会再次启动。
有谁知道如何解决这个问题?
简单代码:
public Form1()
{
InitializeComponent();
timerTest.Tick += new EventHandler(timerTest_Tick);
timerTest.Interval = 1000;
timerTest.Start();
}
private void buttonTest_Click(object sender, EventArgs e)
{
push = true;
}
private void timerTest_Tick(object sender, EventArgs e)
{
ticks++;
labelTest.Text = ticks.ToString();
if(running == false)
{
running = true;
backgroundWorkerTest.RunWorkerAsync();
}
}
public void activate()
{
timerTest.Stop();
timerTest.Interval = 4000;
timerTest.Start();
}
private void DoWork(object sender, DoWorkEventArgs e)
{
while(running)
{
if(push == true)
{
activate();
}
}
}
private void Completed(object sender, RunWorkerCompletedEventArgs e)
{
running = false;
}
}
}
答案 0 :(得分:0)
您永远不会将push
设置为false。
因此,以下代码:
while(running)
{
if(push == true)
{
activate();
}
}
会在紧急循环中不断调用activate()
。 activate()
停止计时器然后重新启动计时器,调用它之间的时间将远远小于计时器间隔。因此,定时器永远不会留下足够的时间来发射。
在任何情况下,为什么不直接从activate()
致电buttonTest_Click()
?
答案 1 :(得分:0)
尝试使用UI线程调度程序调用您的activate
方法。 (假设赢表?)
this.Invoke(new Action(activate));
原因是您的timer
是一个UI控件,并且您在单独的线程上更新Interval
。这将抛出跨线程异常。
为什么您没有看到异常?当DoWork
中的BackgroundWorker
方法引发异常时,它将传播到{{1} } 方法。因此,您应该始终查看Completed
以查看是否发生了异常。
e.Error
答案 2 :(得分:0)
我花了一段时间,但我发现了什么是错的。我会给你发一个工作代码,万一有人会遇到同样的问题。
公共部分类Form1:表单 { public int ticks = 0; public bool running = false; public bool push = false;
public Form1()
{
InitializeComponent();
timerTest.Tick += new EventHandler(timerTest_Tick);
timerTest.Interval = 1000;
timerTest.Start();
}
private void buttonTest_Click(object sender, EventArgs e)
{
push = true;
}
private void timerTest_Tick(object sender, EventArgs e)
{
ticks++;
labelTest.Text = ticks.ToString();
if(running == false)
{
running = true;
backgroundWorkerTest.RunWorkerAsync();
}
}
public void activate()
{
ZmienIntervalNaAwaryjny = true;
}
public bool ZmienIntervalNaAwaryjny = false;
private void DoWork(object sender, DoWorkEventArgs e)
{
if(push == true)
{
activate();
}
}
private void Completed(object sender, RunWorkerCompletedEventArgs e)
{
if(ZmienIntervalNaAwaryjny == true)
{
timerTest.Stop();
timerTest.Interval = 12000;
timerTest.Start();
}
ZmienIntervalNaAwaryjny = false;
running = false;
}
}
答案 3 :(得分:0)
我可以看到这是很久以前问过的,但仅供参考:
一般来说,与后台工作程序(任务)结合使用计时器或线程(记住计时器是system.threading)时,切勿在不知道工作程序正在做什么的情况下尝试随机更改线程属性。
在分配DoWork处理程序以同时准备后台工作程序Progress和Complete处理程序时,这始终是一个好习惯。 在每个周期,报告进度或完成情况,这将使您有机会进行检查并根据需要修改其他线程属性。
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (!worker.CancellationPending)
{
// do task 1 as per the timer1 interval
// do task 2 as per such and such .....
// if I call ChangeInterval here I'll be fiddling with another thread when
// this is still in progress
// that a full loop, Progress will be reported now
}
}
private void backgroundWorker1_ProgressChanged(object sender,ProgressChangedEventArgs e)
{
// Now as the Do work is not in progress
// do something
// check if the user wanted to change the interval ?
// if yes then
ChangeInterval(6000);
// here the progress reporting is done so it will go back to DoWork with the
// NewInterval Value in place and the timer enabled
}
private void ChangeInterval(int NewInterval)
{
timer1.Enabled =false;
timer1.Interval = NewInterval;
timer1.Enabled = true;
}