我一直在尝试为我的计时器和后台工作者线程提供正确的逻辑。虽然我阅读了所有内容,但我并不完全了解整个系统。以下是有关代码的摘录: 我的投票按钮:
private void pollStart_Click(object sender, EventArgs e)
{
tst_bgw = new BackgroundWorker();
//mandatory. Otherwise will throw an exception when calling ReportProgress method
tst_bgw.WorkerReportsProgress = true;
//mandatory. Otherwise we would get an InvalidOperationException when trying to cancel the operation
tst_bgw.WorkerSupportsCancellation = true;
tst_bgw.DoWork += tst_bgw_DoWork;
tst_bgw.ProgressChanged += tst_bgw_ProgressChanged;
tst_bgw.RunWorkerCompleted += tst_bgw_RunWorkerCompleted;
tst_bgw.RunWorkerAsync();
}
我认为到目前为止
我的后台工作线程:
private void tst_bgw_DoWork(object source, DoWorkEventArgs e)
{
m_timer = new System.Timers.Timer();
m_timer.Interval = 1000;
m_timer.Enabled = true;
m_timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
if (tst_bgw.CancellationPending)
{
e.Cancel = true;
return;
}
}
和已过去的层事件代码:
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
if (powerVal > 3250)
{
m_timer.Stop();
tst_bgw.CancelAsync();
}
else
{
string pow;
int progressVal = 100 - ((3250 - powerVal) / timerVal);
uiDelegateTest tstDel = new uiDelegateTest(recvMessage);// the recvMessage function takes a textbox as an argument and directs output from socket to it.
pow = construct_command("power", powerVal);
sData = Encoding.ASCII.GetBytes(pow);
if (active_connection)
try
{
m_sock.Send(sData);
Array.Clear(sData, 0, sData.Length);
tstDel(ref unit_Output);// Read somewhere that you can only modify UI elements in this method via delegate so I think this is OK.
m_sock.Send(time_out_command);
tstDel(ref unit_Output);
tst_bgw.ReportProgress(progressVal);
}
catch (SocketException se)
{
MessageBox.Show(se.Message);
}
tst_bgw.ReportProgress(powerVal, progressVal);
powerVal = powerVal + pwrIncVal;
}
我只想知道其他一些事情;我使用正确的计时器(不是我认为它应该很重要,但有人建议这可能是我想做的最好的计时器)并且我真的可以通过代表修改DoWork方法中的UI元素,如果是的话这样做有特殊的考虑因素。 对于长篇帖子感到抱歉,谢谢你的时间。
答案 0 :(得分:1)
此代码有很多错误。
1)您没有处置您的后台工作人员。背景工人必须在使用后进行处理。它们被设计用作winforms组件,通常会通过设计器添加到窗口中。这将确保它与表格一起创建并在表格处理时处理 2)你在dowork方法中所做的就是创建一个新计时器并运行它。在背景工作者中没有任何意义,因为无论如何它会很快发生 3)每次再次运行后台工作程序时,您将重新创建计时器。但你永远不会停止或处理旧计时器,你只是覆盖了会员。
我建议您完全摆脱BackgroundWorker并使用计时器。在表单构造函数中创建计时器,并确保在窗体dispose方法中处理它。 (或者使用设计器将其添加到表单中)。在pollstart_click方法中,只需启动计时器。 (如果你有一个轮询停止方法,你可以在那里停止计时器)
答案 1 :(得分:1)
您不需要BackgroundWorker和Timer来实现目标。根据您发布的内容,您似乎希望让用户单击一个按钮,该按钮启动在证书点退出的轮询过程。
您的投票模型确实表明计时器可以正常工作。
如果使用Timer,我会在InitializeComponent()调用之后用
之类的方式初始化定时器private void InitializeTimer()
{
this.timer = new Timer();
int seconds = 1;
this.timer.Interval = 1000 * seconds; // 1000 * n where n == seconds
this.timer.Tick += new EventHandler(timer_Tick);
// don't start timer until user clicks Start
}
button_click只是
private void button_Click(object sender, EventArgs e)
{
this.timer.Start();
}
然后在timer_Tick上你需要进行轮询,如果计时器在这样的UI线程上,你应该可以从那里更新你的UI
void timer_Tick(object sender, EventArgs e)
{
if( determineIfTimerShouldStop() )
{
this.timer.Stop();
}
else
{
// write a method to just get the power value from your socket
int powerValue = getPowerValue();
// set progressbar, label, etc with value from method above
}
}
但是,如果计时器线程与UI不在同一个线程上,则在尝试更新UI时会出现异常。在这种情况下,您可以使用DataDink提及的调用并执行类似此操作的
void timer_Tick(object sender, EventArgs e)
{
if( determineIfTimerShouldStop() )
{
this.timer.Stop();
}
else
{
// write a method to just get the power value from your socket
int powerValue = getPowerValue();
// set a label with Invoke
mylabel.Invoke(
new MethodInvoker( delegate { mylabel.Text = "some string"; } )
);
}
}
鉴于您发布的代码,您实际上不需要同时使用BackgroundWorker和Timer,但我有一些实例,我在调用计时器时使用BackgroundWorker来工作,这样我就可以更新计时器UI定期并有一个手动按钮来刷新UI。但我并没有像你那样更新我的用户界面。
如果您仍然需要同时执行这两项操作,那么大致就是如何使您的应用程序流动...