决定不使用任何计时器。 我做的更简单。
添加了背景工作者。 在加载了所有构造函数后,在已显示的事件中添加了一个Shown事件。 在显示的事件中,我启动了backgroundworker异步。
在后台工作人员DoWork中:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while(true)
{
cpuView();
gpuView();
Thread.Sleep(1000);
}
}
答案 0 :(得分:6)
在这种情况下,最好使用两个System.Threading.Timer
并在这两个线程中执行cpu密集型操作。请注意,必须使用BeginInvoke
访问控件。您可以将这些访问封装到属性设置器中,甚至可以更好地将它们拉出到视图模型类中。
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);
}
答案 1 :(得分:2)
您不能将此代码抛入后台工作程序并期望它能够正常工作。需要在主线程上调用更新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.
在后台工作者Completed()方法中:
// Update the UI elements based on your results from the worker thread
// Re-enable the timer.
答案 2 :(得分:2)
首先要确保能够解决多重呼吸困难问题(尤其是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()
将无法正常工作。
答案 3 :(得分:1)
是的,你可以:
在您的计时器刻度事件中:
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);
}
}
答案 4 :(得分:0)
我认为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();
}
}
}
答案 5 :(得分:0)
在我的情况下,我在 WinForm BackgroundWorker , System.Timers.Timer 和 ProgressBar >申请。我遇到的是第二个问题,我将重复BackgroundWorker的工作我尝试在BackgroundWorker的ProgressChanged中更新ProgressBar时得到跨线程异常。然后我找到了一个< SO @ Rudedog2 https://stackoverflow.com/a/4072298/1218551上的strong>解决方案,它说当初始化Timers.Timer对象以用于Windows窗体时,必须将timer实例的SynchronizingObject属性设置为窗体。 / p>
systemTimersTimerInstance.SynchronizingObject = this; // this = form instance.