即時通訊構建一個桌面應用程序,每隔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