そのデータをwinformに表示するためにx秒間隔ごとにデータベースからデータを取得するデスクトップアプリケーションを構築しています.GUIをブロックしたくありません.データを取得するメソッドに時間がかかるかどうかは気にしません.チェック間隔、GUI とは非同期のメソッドが必要です。最適なアプローチは何ですか?またその理由は何ですか? スレッドの初心者に感謝します!
バックグラウンドワーカー?スレッドスリープ? 手動リセットイベント?
そのデータをwinformに表示するためにx秒間隔ごとにデータベースからデータを取得するデスクトップアプリケーションを構築しています.GUIをブロックしたくありません.データを取得するメソッドに時間がかかるかどうかは気にしません.チェック間隔、GUI とは非同期のメソッドが必要です。最適なアプローチは何ですか?またその理由は何ですか? スレッドの初心者に感謝します!
バックグラウンドワーカー?スレッドスリープ? 手動リセットイベント?
したがって、X 秒ごとにタスクを実行したいと言うことから始めます。これは、タイマーが必要であることを示しています。ただし、選択できるものはたくさんあります。 System.Timer
私たちの目的には問題なく動作するはずですが、使用したい場合は使用System.Windows.Forms.Timer
できます。フォームを開いたときにタイマーを開始し、間隔を希望どおりに構成し、タイマーが起動したときに実行するハンドラーを割り当てます。
次に、タイマーが起動したら、データベース呼び出しを実行して UI を更新する必要があります。長時間実行される操作を実行し、結果を使用して UI を更新することは、このBackgroundWorker
クラスが目的に合わせて作成されたものです。DoWork
データベース呼び出しを行うメソッドを設定WorkerCompleted
し、結果に基づいてイベントで UI を更新します。(完了イベントは UI スレッドで自動的に実行されます。そのスレッドに手動でマーシャリングする必要はありません。)
十分に新しいバージョンの C# を使用している場合は、Tasks を使用してこれらと同じことを行うこともできます。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!";
}
このベースの例を機能させるには、タイマーを使用して、ティック イベントが UI スレッドで実行されるようにTask
する必要があることに注意してください。System.Windows.Forms.Timer
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`.");
}
}
}