安全地从后台线程每30秒更新一次GUI
本文探讨如何在应用程序中安全地使用线程,避免错误,实现每30秒从后台线程更新GUI的需求。
用户最初尝试使用BackgroundWorker并在while循环中运行它,但由于后台工作线程不是STA线程而导致异常。
正确的做法是将数据库调用与GUI更新分开。数据库调用应在后台线程(使用BackgroundWorker)中执行。调用完成后,触发进度事件通知主线程更新GUI。
用户提供的代码展示了这种方法:
<code class="language-C#">public class UpdateController { private UserController _userController; private BackgroundWorker _backgroundWorker; // ... public void Update() { _backgroundWorker.RunWorkerAsync(); } void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { // UI 更新 _userController.UpdateUsersOnMap(); Update(); // 此处存在潜在问题,递归调用可能导致堆栈溢出 } public void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { // 大型数据库任务 } }</code>
然而,用户面临另一个挑战:如何每30秒触发一次更新。在RunWorkerCompleted
事件处理程序中添加10秒的休眠不可行,因为它会冻结GUI。
为了解决这个问题,可以使用一个Timer定期调用Update
方法,该方法依次启动数据库调用和随后的GUI更新。 更佳方案是避免在RunWorkerCompleted
中递归调用Update()
,而是使用System.Timers.Timer
或System.Windows.Forms.Timer
来控制更新频率。 这将确保GUI保持响应,并避免潜在的堆栈溢出错误。
建议的改进代码结构如下 (使用 System.Timers.Timer
):
<code class="language-C#">public class UpdateController { private UserController _userController; private BackgroundWorker _backgroundWorker; private System.Timers.Timer _timer; public UpdateController() { _backgroundWorker = new BackgroundWorker(); _backgroundWorker.DoWork += backgroundWorker_DoWork; _backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted; _timer = new System.Timers.Timer(30000); // 30秒 _timer.Elapsed += Timer_Elapsed; _timer.AutoReset = true; } public void Start() { _timer.Start(); } private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { _backgroundWorker.RunWorkerAsync(); } void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { // UI 更新,确保在UI线程执行 _userController.BeginInvoke(new Action(() => _userController.UpdateUsersOnMap())); } public void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { // 大型数据库任务 } }</code>
这个改进的代码利用Timer来控制更新频率,避免了递归调用带来的风险,并使用BeginInvoke
确保UI更新在UI线程上执行,从而保证GUI的响应性。 记住在适当的时候调用 _timer.Stop()
来停止定时器。
以上是如何每 30 秒从后台线程安全地更新一次 GUI?的详细内容。更多信息请关注PHP中文网其他相关文章!