ハードウェア スイッチを定期的にチェックするために BackgroundWorker を使用しています。低速の RS485 ネットワークで接続されているため、次のステータス更新を遅らせなければなりません。On switch Status change OK/nOK Picture Box を更新したい。これは、nOK pictureBox 上の緑色の OK pictureBox として実現されます。ここでは実際の作業は行われません。
拡張性のために、Backgroundworker を使用することにしました。最後に、非表示のワーカーが必要です。
- 3 つのスイッチのステータスをグローバルに提供し、
- StatusChange の更新 PictureBoxes。
問題 の説明 BackgroundWorker が開始されると、期待どおりに動作します。ただし、GUI はフリーズします。
私は何を試しましたか?MSDN BackgroundWorker Class Note 1には 、 ProgressChanged を介して GUI を更新する必要があると書かれています。Worker_Switch.ReportProgress(fakeProgress++) でこのイベントを発生させようとしましたが、失敗しました。PictureBox は更新されなくなりました。
デザイナーのスニペット
this.Worker_Switch = new System.ComponentModel.BackgroundWorker();
//
// Worker_Switch
//
this.Worker_Switch.WorkerSupportsCancellation = true;
this.Worker_Switch.DoWork += new System.ComponentModel.DoWorkEventHandler(this.Worker_Switch_DoWork);
メイン フォームのスニペット
delegate void SetEventCallback(object sender, DoWorkEventArgs e); // Threadsafe calls for DoWork
private void btnBackgroundworker_Click(object sender, EventArgs e)
{
if (!Worker_Switch.IsBusy)
{
Worker_Switch.RunWorkerAsync();
}
}
private void Worker_Switch_DoWork(object sender, DoWorkEventArgs e)
{
// Worker Thread has no permission to change PictureBox "pictureBoxSwitchrightOK"
// Therefore this method calls itsself in the MainThread, if necessary.
while (!Worker_Switch.CancellationPending)
{
if (this.pictureBoxSwitchrightOK.InvokeRequired) // Worker Thread
{
System.Threading.Thread.Sleep(400);
SetEventCallback myCall = new SetEventCallback(Worker_Switch_DoWork);
this.Invoke(myCall, new object[] { sender, e });
}
else // Main Thread
{
// Turns OK Picture Box invisible, if nOk State (Switch pushed)
pictureBoxSwitchrightOK.Visible = SwitchOK("right"); // true: OK (green)
this.Refresh();
}
}
private bool SwitchOK(string rightOrLeft) // select one of the switches
{ (...)} // gets hardware switch status
編集: laszlokiss88(3つの可能性)とJMK(System.Windows.Forms
ツールボックスのタイマーで簡単にするため)に特別な感謝
Toolbox のこの代替手段も機能しました。
this.timer_Switch.Enabled = true;
this.timer_Switch.Interval = 400;
this.timer_Switch.Tick += new System.EventHandler(this.timer_Switch_Tick);
private void timer_Switch_Tick(object sender, EventArgs e)
{
motorSwitchControl.Init(); // globally available Switch status
SwitchRight = SwitchOK("right");
SwitchRightOK.Visible = SwitchRight;
SwitchLeft = SwitchOK("left"); // globally available Switch status
SwitchLeftOK.Visible = SwitchLeft;
SwitchAllOK = SwitchRight & SwitchLeft;
this.Refresh();
}
a) Sleep() が実際にワーカー スレッドで発生するのは正しいですか? - メインスレッドなし
b) DoWork でユーザー インターフェイス オブジェクトを操作すると、何が問題になりますか? (MSDN Note に反して) - メイン スレッドで動作しますか?
c) PictureBox を定期的に更新する正しい方法は何ですか? DoWork、ProgressChanged、RunWorkerCompleted...? - lazlokiss88 の回答からの 3 つの可能性。