[英]Changing Timer Interval in Backgroundworker DoWork Disables the Timer [C#]
我在更改后台工作人員的 DoWork 事件中的計時器間隔時遇到問題。 通過單擊按鈕更改間隔時,計時器停止並且不會再次啟動。
有誰知道如何解決這個問題?
簡單代碼:
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;
}
}
}
您永遠不會將push
設置為 false。
因此,以下代碼:
while(running)
{
if(push == true)
{
activate();
}
}
將在一個緊密的循環中連續調用activate()
。 activate()
停止計時器然后重新啟動它,調用它的時間將遠小於計時器間隔。 因此,定時器將永遠不會被留下足夠長的時間來觸發。
無論如何,為什么不直接從buttonTest_Click()
調用activate()
buttonTest_Click()
呢?
我可以看到很久以前就有人問過這個問題,但僅供參考:
當談到一般的計時器或線程(記住計時器是 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;
}
嘗試使用 UI 線程的 Dispatcher 調用您的activate
方法。 (假設獲勝形式? )
this.Invoke(new Action(activate));
原因是您的timer
是一個 UI 控件,並且您正在一個單獨的線程上更新Interval
。 這將引發跨線程異常。
為什么你看不到異常? 當BackgroundWorker
的DoWork
方法拋出異常時,它將被傳播到Completed
方法。 因此,您應該始終查看e.Error
以查看是否發生了異常。
private void Completed(object sender, RunWorkerCompletedEventArgs e)
{
if(e.Error != null)
{
// Oh no something went wrong...
}
running = false;
}
我花了一段時間,但我發現出了什么問題。 我會向您發布一個工作代碼,以防萬一有人遇到同樣的問題。
公共部分類 Form1 : Form { public int ticks = 0; 公共布爾運行=假; 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;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.