バックグラウンド
ここで受け取った貴重なアドバイスから、データベースを集中的に使用するすべてのコードをバックグラウンドワーカーに移動しました。具体的には、データベースへの直接呼び出しです。そのコードは、backgroundworkerのDoWorkイベント中に実行されます。DoWorkイベント中にDataTableが返される場合は、そのDataTableをクラス全体の変数に設定します。これは、このコードを実行するたびにDataTableを必要とするコントロールを呼び出す必要がないようにするために行われます。
そのコードが実行されている間、何かが起こっていることをユーザーに知らせるために、メインUIスレッドで更新されるラベルがあります。ラベルを更新するには、750ミリ秒ごとに「。」となるようにタイマーを使用します。ラベルの文字列に追加されます。
私が最初に気付いたのは、backgroundworkerのRunWorkerCompletedイベントがトリガーされていないことでした。これを解決するためApplication.DoEvents();
に、バックグラウンドワーカーに電話をかける前に行いました。それは醜いものでしたが、それがイベントを引き起こしました。誰かがこれを修正するための代替手段を持っているなら、私はすべての耳です。
それから私は興味深い苦境に出くわしました。Visual Studio 2010内でプログラムをデバッグモードで実行すると、「クロススレッド操作が無効です:作成されたスレッド以外のスレッドからアクセスされたコントロール'lblStatus'」というInvalidOperationExceptionエラーが発生します。このエラーは、バックグラウンドワーカーのRunWorkerCompletedイベント中に発生します。このイベントでは、メインUIスレッドでラベルのテキストを設定しました。ただし、実行可能ファイルを介してアプリケーションを直接起動すると、希望どおりに機能します(つまり、ラベルのテキストが正しく設定されます)。
質問
誰かが何が起こっているのかを説明したり、これを改善する方法についてアドバイスを提供したりできますか?
コード
関連するすべてのコードを投稿することはできませんが、関連するものをいくつか示します。
namespace Test
{
public partial class frmMain : Form
{
public static Boolean bStatus = false;
static Boolean bTimer = false;
System.Timers.Timer MyTimer = new System.Timers.Timer();
public frmMain()
{
InitializeComponent();
MyTimer.Elapsed += new System.Timers.ElapsedEventHandler(MyTimer_Elapsed);
MyTimer.Interval = 750; // Every 3/4 of a second
ExampleTrigger();
}
/// <Insert>Lots of unshown code here</Insert>
private void ExampleTrigger()
{
// This is used to simulate an event that would require the backgroundworker
Application.DoEvents();
bgw.RunWorkerAsync(0);
WaitText("Example - 1");
}
private static void MyTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
bTimer = true;
}
// Update status text
private void WaitText(string txt)
{
MyTimer.Enabled = true;
lblStatus.Text = txt;
bStatus = false;
while (!bStatus)
{
if (bTimer)
{
txt = txt + ".";
lblStatus.Text = txt;
lblStatus.Update();
bTimer = false;
}
}
MyTimer.Enabled = false;
}
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
int iSelect = (int)e.Argument;
switch (iSelect)
{
case 0:
// Hit the database
break;
/// <Insert>Other cases here</Insert>
default:
// Do something magical!
break;
}
}
private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
bStatus = true;
lblStatus.Text = "Ready!"; // This is where the exception occurs!
}
}
}