即时通讯构建一个桌面应用程序,每隔x秒间隔从数据库检索数据,以便将数据显示到winform,我不想阻止我的GUI,我不在乎如果方法检索数据需要一段时间,而这段时间少于检查间隔,我希望该方法与gui异步,什么是最好的方法,为什么?感谢新的线程!从gui执行异步方法的最佳方法
后台工作者? Thread.sleep? ManualResetEvent?
即时通讯构建一个桌面应用程序,每隔x秒间隔从数据库检索数据,以便将数据显示到winform,我不想阻止我的GUI,我不在乎如果方法检索数据需要一段时间,而这段时间少于检查间隔,我希望该方法与gui异步,什么是最好的方法,为什么?感谢新的线程!从gui执行异步方法的最佳方法
后台工作者? Thread.sleep? ManualResetEvent?
正如卡米尔指出的,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`.");
}
}
}
我有网络框架3.5,这个例子适合我!,但我不需要在DoWork事件中使用thread.sleep?例如: Thread.Sleep(1000);方法(参数); –
跳过'Thread.Sleep(1000);'...而是将您的计时器设置为每1000毫秒打勾一次。这通常是在设计器中配置的,所以我不打扰如何手动编写代码。 – jp2code
所以,你开始说你想每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
计时器,以便Tick事件在UI线程中运行。
@dotNETbeginner一般而言,您是正确的,这是我如何使用这个特定的任务,需要它使用窗体计时器。对'FromCurrentSynchronizationContext'的调用抓取当前上下文。如果当前上下文是后台线程,则后续将在后台线程中运行。我们需要“当前上下文”作为UI线程,并且窗体计时器将确保事件处理程序在UI线程中运行。还有其他方法可以在不使用窗体计时器的情况下访问同步上下文,我只是选择这样做。 – Servy
使用'Task'类。 – SLaks
请注意,'Task'类在.NET 4.0及更新版本中可用。 – Kamil