我正在构建一个桌面应用程序,它每隔 x 秒间隔从数据库中检索数据以将该数据显示到 winform,我不想阻止我的 gui,我不在乎检索数据的方法是否需要时间,而该时间小于检查间隔,我希望该方法与 gui 异步,什么是最好的方法,为什么?感谢我是线程新手!
后台工作者?线程.sleep?手动重置事件?
我正在构建一个桌面应用程序,它每隔 x 秒间隔从数据库中检索数据以将该数据显示到 winform,我不想阻止我的 gui,我不在乎检索数据的方法是否需要时间,而该时间小于检查间隔,我希望该方法与 gui 异步,什么是最好的方法,为什么?感谢我是线程新手!
后台工作者?线程.sleep?手动重置事件?
所以你开始说你想每 X 秒执行一次任务。这告诉我们需要一个计时器。不过有很多选择。 System.Timer
对于我们的目的应该可以正常工作,但如果你想使用System.Windows.Forms.Timer
你可以。您需要在打开表单时启动计时器,将间隔配置为您想要的,并分配一个处理程序以在计时器触发时运行。
接下来,当计时器触发时,您需要执行数据库调用并更新 UI。执行长时间运行的操作,然后使用结果更新 UI 是BackgroundWorker
该类的目的。设置DoWork
执行数据库调用的方法,并让WorkerCompleted
事件根据结果更新 UI。(完成的事件将自动在 UI 线程中运行;您无需手动编组到该线程。)
如果你有足够新的 C# 版本,你也可以使用任务来做同样的事情。您可以使用Task.Factory.StartNew
数据库调用使其在后台线程中运行,然后您可以调用ContinueWith
它Task
返回并使用允许您指定同步上下文的重载。这是一个简单的例子:
private void handler(object sender, EventArgs e)
{
Task.Factory.StartNew(() => getInfoFromDB())
.ContinueWith(task => label1.Text = task.Result,
CancellationToken.None, TaskContinuationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
}
private string getInfoFromDB()
{
Thread.Sleep(2000);//simulate long IO operation
return "Hello world!";
}
请注意,要使此Task
基于示例的工作正常,您需要使用System.Windows.Forms.Timer
计时器,以便在 UI 线程中运行滴答事件。
正如 Kamil 所指出的,Tasks
在 .NET 4.0 之前的版本中不可用。
如果你被困在黑暗时代,BackgroundWorker 在这方面做得很好。事实上,这可能就是它的创建目的!
未经测试的伪代码:
public partial class Form1 : Form {
private bool ok;
private BackgroundWorker worker;
public Form1() {
InitializeComponent();
worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
ok = true;
}
private void timerTick(object sender, EventArgs e) {
if (!worker.IsBusy) {
worker.RunWorkerAsync();
}
}
private void worker_DoWork(object sender, DoWorkEventArgs e) {
var w = (BackgroundWorker)sender;
MyData inputData = (MyData)e.Argument;
for (int i = 0; (i < NUM_TASKS) && !worker.CancellationPending; i++) {
w.ReportProgress(i);
// do tasks
}
e.Result = SomethingYouWantReturned();
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) {
if (!ok) {
worker.CancelAsync();
}
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (e.Error != null) {
ok = false;
MessageBox.Show(this, e.Error.Message, "Error!");
} else {
var item = (TypeYouWantedReturned)e.Result;
Console.WriteLine("Do something with `item`.");
}
}
}