2012-01-26 10 views
1

チーム、
は私がデータベースにアップロードデータを行いVB.Net Windowsアプリケーションを構築しており、基本的に2つのコントロール更新:
1であるテキストボックスをデータベースレコードのアップロードごとに1行で常に更新されます。
2.アップロードされたデータベースレコードの数を記録するラベル。VB.Net Winフォームアプリケーション - UIの更新問題

スレッドのbgwWorker_DoWork()メソッドにアップロード用のビジネスロジックが含まれ、bgwWorker_ProgressChanged()がアップロードに基づいて2つのUIコントロールを更新するBackgroundWorker thread概念を使用しました。

しかし、私が直面している問題は、両方のUIコントロールで完全な更新が得られないということです。時々、スレッドは、テキストボックスの更新や、時にはラベルの更新をバイパスします。私は、各UIコントロールの更新コードの前にSystem.Threading.Thread.Sleep(25)を追加することで、この問題を解決できました。これは問題を解決する正しい方法ですか?私は行方不明の何かがありますか?

お勧めです。以下は

両方のこれらのメソッドのコードです:

Private Sub bgwWorker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgwWorker.DoWork 
    ................. 
    ................. 
    'Updates database record related update in textbox 
    System.Threading.Thread.Sleep(25) 
    updater.eventName = "UpdateStatusBox" 
    updater.errorMessageToLog = String.Empty 
    updater.errorMessageToLog += GetErrorMessage(dataTable(rowNumber)("Name").ToString(), ExceptionData) 
    bgwWorker.ReportProgress(1, updater) 

    ................. 
    ................. 
    'Updates Status Count in LABEL 
    System.Threading.Thread.Sleep(25) 
    updater.eventName = "UpdateStatusBar" 
     updater.successCount = successCount.ToString() 
     updater.failureCount = failureCount.ToString() 
     bgwWorker.ReportProgress(2, updater) 
End Sub 

Private Sub bgwWorker_ProgressChanged(ByVal sender As System.Object, ByVal e As ProgressChangedEventArgs) Handles bgwWorker.ProgressChanged 
     Dim updater As UIUpdater = TryCast(e.UserState, UIUpdater) 

    .......................................... 
     If updater.eventName = "UpdateStatusBar" Then 
      UpdateStatusBar(updater.successCount, updater.failureCount) 
     ElseIf updater.eventName = "UpdateStatusBox" Then 
      txtUpdates.Text = txtUpdates.Text & updater.errorMessageToLog 
     End If 
     ..................................... 
End Sub 

答えて

4

あなたの問題は、updaterというUIUpdaterオブジェクトのインスタンスであるとほとんど肯定的です。このオブジェクトはグローバルに宣言されているように見え、呼び出し間で共有されます。

updater.eventName = "UpdateStatusBox" 
bgwWorker.ReportProgress(1, updater) 

updater.eventName = "UpdateStatusBar" 
bgwWorker.ReportProgress(2, updater) 

あなたが直線的にReportProgress()を呼び出しますが、それはすぐにあなたのProgressChangedイベントを発生しませんもそのメソッドが完了するまで、それがブロックしない:これはあなたが持っているもので、コードを少し省略

。これを行うには、それについて考えるならスレッドの目的を破るでしょう。

別の言い方をすると、プロパティを設定するグローバルオブジェクトがあります。次に、「誰かがチャンスを得たら、これで何かをする」と言う。そのグローバルオブジェクトのプロパティを変更すると、ときどきこれが起こります。より前に「誰かが何かしたことが起こりました」が発生します。

解決策は、可能なイベントごとに1つずつ、または必要なときにインスタンス変数を作成するために、2つのグローバル変数を作成することです。グローバル変数を使用するのにスレッドセーフではないので、インスタンス変数を作成することをお勧めします。実際には、ReportProgressに渡す状態オブジェクトは単なる文字列である可能性があります。

+0

あなたは絶対にスポットにいました。私はこのコードを使って問題を理解し、このような美しい方法で私を説明してくれてありがとう!君に乾杯!!! :) –

0

私はあなたのDoWorkイベントで睡眠を使用することはありません。

コントロールの更新後にコントロールをリフレッシュしようとしましたか?各コントロールには、再描画を強制するRefreshメソッドがあります。これはちらつきを引き起こすかもしれません。

もう1つの方法は、2回の呼び出しを試みるのではなく、ReportProgressを1回呼び出すだけで、両方のコントロール(テキストボックスとラベル)に必要な情報を含めることです。

+0

ちょっとBenR - 提案をありがとう。 Chrisが提案したように、この問題は、これらのProgessUpdates呼び出しのすべてで同じUIUpdaterオブジェクトが使用されていることが原因でした。これは間接的に私が自分のコードを書いた方法でスレッドの概念を無効にします。乾杯! :) –

関連する問題