如何使用带有计时器滴答的BackgroundWorker?

决定不使用任何计时器。 我做的更简单。

添加了一个后台工作者。 在加载了所有构造函数后,添加了一个Shown事件,显示事件触发。 在Shown事件中,我启动了backgroundworker异步。

在后台工作者DoWork我做:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { while(true) { cpuView(); gpuView(); Thread.Sleep(1000); } } 

在这种情况下,最好使用两个System.Threading.Timer并在这两个线程中执行cpu密集型操作。 请注意,您必须使用BeginInvoke访问控件。 您可以将这些访问封装到属性setter中,甚至可以将它们更好地提取到视图模型类中。

 public class MyForm : Form { private System.Threading.Timer gpuUpdateTimer; private System.Threading.Timer cpuUpdateTimer; protected override void OnLoad(EventArgs e) { base.OnLoad(e); if (!DesignMode) { gpuUpdateTimer = new System.Threading.Timer(UpdateGpuView, null, 0, 1000); cpuUpdateTimer = new System.Threading.Timer(UpdateCpuView, null, 0, 100); } } private string GpuText { set { if (InvokeRequired) { BeginInvoke(new Action(() => gpuLabel.Text = value), null); } } } private string TemperatureLabel { set { if (InvokeRequired) { BeginInvoke(new Action(() => temperatureLabel.Text = value), null); } } } private void UpdateCpuView(object state) { // do your stuff here // // do not access control directly, use BeginInvoke! TemperatureLabel = sensor.Value.ToString() + "c" // whatever } private void UpdateGpuView(object state) { // do your stuff here // // do not access control directly, use BeginInvoke! GpuText = sensor.Value.ToString() + "c"; // whatever } protected override void Dispose(bool disposing) { if (disposing) { if (cpuTimer != null) { cpuTimer.Dispose(); } if (gpuTimer != null) { gpuTimer.Dispose(); } } base.Dispose(disposing); } 

您不能将此代码抛入后台工作程序并期望它能够正常工作。 需要在主线程上调用更新UI元素(标签,文本框,…)的任何内容。 您需要打破逻辑以获取更新UI的数据和逻辑。

我想说你最好的办法就是这样做:

在计时器Tick()方法中:

 // Disable the timer. // Start the background worker 

在后台worker DoWork()方法中:

 // Call your functions, taking out any code that // updates UI elements and storing this information // somewhere you can access it once the thread is done. 

在后台worker Completed()方法中:

 // Update the UI elements based on your results from the worker thread // Re-enable the timer. 

首先要确保能够解决多重呼吸困难问题(尤其是UI问题)。

然后你可以使用像

 public class Program { public static void Main(string[] args) { Timer myTimer = new Timer(TimerTick, // the callback function new object(), // some parameter to pass 0, // the time to wait before the timer starts it's first tick 1000); // the tick intervall } private static void TimerTick(object state) { // less then .NET 4.0 Thread newThread = new Thread(CallTheBackgroundFunctions); newThread.Start(); // .NET 4.0 or higher Task.Factory.StartNew(CallTheBackgroundFunctions); } private static void CallTheBackgroundFunctions() { cpuView(); gpuView(); } } 

请记住(就像John Koerner告诉你的那样)你的cpuView()gpuView()将无法正常工作。

是的你可以:

在您的Timer tick事件中:

 private void timer_Tick(object sender, EventArgs e) { timer.Enabled = false; backgroundworker.RunWorkerAsync(); timer.Enabled = true; } 

在你的Backgroundworker dowork活动中:

 private void backgroundworker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) { try { //Write what you want to do } catch (Exception ex) { MessageBox.Show("Error:\n\n" + ex.Message, "System", MessageBoxButtons.OK, MessageBoxIcon.Error); } } 

我认为BackgroundWorker对于这种情况来说太复杂了; 使用Timer很难实现保证停止。

我想建议您使用工作Thread与循环等待取消ManualResetEvent所需的时间间隔:

  • 如果设置了取消事件,则工作人员退出循环。
  • 如果超时(您需要的时间间隔超过),则执行系统监视。

这是代码的草案版本 。 请注意我没有测试过 ,但它可以告诉你这个想法。

 public class HardwareMonitor { private readonly object _locker = new object(); private readonly TimeSpan _monitoringInterval; private readonly Thread _thread; private readonly ManualResetEvent _stoppingEvent = new ManualResetEvent(false); private readonly ManualResetEvent _stoppedEvent = new ManualResetEvent(false); public HardwareMonitor(TimeSpan monitoringInterval) { _monitoringInterval = monitoringInterval; _thread = new Thread(ThreadFunc) { IsBackground = true }; } public void Start() { lock (_locker) { if (!_stoppedEvent.WaitOne(0)) throw new InvalidOperationException("Already running"); _stoppingEvent.Reset(); _stoppedEvent.Reset(); _thread.Start(); } } public void Stop() { lock (_locker) { _stoppingEvent.Set(); } _stoppedEvent.WaitOne(); } private void ThreadFunc() { try { while (true) { // Wait for time interval or cancellation event. if (_stoppingEvent.WaitOne(_monitoringInterval)) break; // Monitoring... // NOTE: update UI elements using Invoke()/BeginInvoke() if required. } } finally { _stoppedEvent.Set(); } } } 

在我的例子中,我在WinForm应用程序中使用了BackgroundWorkerSystem.Timers.TimerProgressBar 。 我遇到的是第二个问题,我将重复BackgroundWorker的Do-Work我在尝试在BackgroundWorker的ProgressChanged中更新ProgressBar时遇到跨线程exception 。然后我在SO @ Rudedog2上找到了一个解决方案 https://stackoverflow.com / a / 4072298/1218551 ,它说初始化Timers.Timer对象以用于Windows窗体时,必须将timer实例的SynchronizingObject属性设置为窗体。

 systemTimersTimerInstance.SynchronizingObject = this; // this = form instance. 

http://msdn.microsoft.com/en-us/magazine/cc164015.aspx