アプリケーションが起動し、アップグレードされたばかりのとき、ローカルデータベースの更新(sqlite)を実行しています。
それはそのようなものです:ユーザーが私のアプリを起動し、次に私がアップグレードプロセスを開始します。このアップグレードプロセス中に、継続的なプログレスバーを持つフォームを表示しています。アップグレードプロセスが完了すると、このフォームは閉じ、ユーザーはアプリケーションの使用を開始できます。
ただし、アップグレードプロセスは非常に集中的であるため、プログレスバーはアニメーション化されません。
古いVB6バージョンでは、フォームが1つあり、プログレスバーが表示されるActiveX-Exeを使用していました。これが私の「バックグラウンドワーカー」でした。
VB.NETで同じアプローチを使用できるかどうかはわかりません。
バックグラウンドワーカーで作業を行う例を見ただけですが、プログレスバー自体がバックグラウンドワーカーである例は見たことがありません。
データベースのアップグレードをブロックする必要があります。データベースのアップグレードが完了する前に、ユーザーが私のアプリケーションを使用することはできません。これは、プログレスバーのみが「アウトプロセス」であり、アップグレードではないことを意味します。
どうもありがとうございました!
最初にこれを読んでください: Application.DoEvents()の使用
したがって、上記の回答を読んだ後は、DoEventsを二度と使用することはなく、DoEventsがないと(および/またはPaintイベントが発生するようにProgressBarを無効化すると)、「アップグレードプロセスが非常に集中するため、プログレスバーはアニメーション化されません」
したがって、Cthulhuのコメント-「プログレスバーを使用してダイアログを作成し、そのダイアログをモーダルにして、バックグラウンドワーカーでdb-stuffを実行できます。」前進するための最良の方法の1つです。
私が使用しているこれのC#実装を翻訳しました。すぐにドロップできるはずです。
これはProgressBarフォームです:
Public Partial Class ThinkingProgressBar
Inherits Form
Private startTime As System.DateTime = DateTime.Now
Public Sub New()
InitializeComponent()
End Sub
Private Sub lblClose_LinkClicked(sender As Object, e As LinkLabelLinkClickedEventArgs)
Me.Tag = "Cancelled"
Me.Hide()
End Sub
Public Sub SetThinkingBar(ByVal switchedOn As Boolean)
If switchedOn Then
lblTime.Text = "0:00:00"
startTime = DateTime.Now
Timer1.Enabled = True
Timer1.Start()
Else
Timer1.Enabled = False
Timer1.Stop()
End If
End Sub
Private Sub timer1_Tick(sender As Object, e As EventArgs)
Dim diff As New TimeSpan()
diff = DateTime.Now.Subtract(startTime)
lblTime.Text = diff.Hours & ":" & diff.Minutes.ToString("00") & ":" & diff.Seconds.ToString("00")
lblTime.Invalidate()
End Sub
End Class
BackgroundWorkerコントロールをフォームにドラッグアンドドロップします。バックグラウンドワーカーのイベントは次のとおりです。
Private Sub backgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
e.Result = e.Argument
'DirectCast(e.Result, ThinkingProgressBar).SetThinkingBar(True)
'DO LONG OPERATION HERE
End Sub
Private Sub backgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
Dim dlg As ThinkingProgressBar = TryCast(e.Result, ThinkingProgressBar)
If IsNothing(dlg) = False Then
dlg.SetThinkingBar(False)
dlg.Close()
End If
End Sub
そして、アプリケーションが起動してアップグレードを行うときの呼び出しコードは次のとおりです。
Dim dlg As New ThinkingProgressBar()
dlg.SetThinkingBar(True)
BackgroundWorker1.RunWorkerAsync(dlg)
dlg.ShowDialog()
If IsNothing(dlg.Tag) = False AndAlso dlg.Tag.ToString() = "Cancelled" Then
Return
End If
いくつかのこととして、ユーザーがキャンセルできないようにすることができます(つまり、lblClose_LinkClicked
)アップグレード中にユーザーがプロセスを強制終了したり、PCの電源を切ったりした場合に対処するために、保護/防御プログラミングを導入します。
また、ProgressBarは実際にはアニメーションGIFです。データベースの更新にかかる時間を見積もるのは非常に難しいため、これは使用法に適しています。
あなたの要件から、あなたが探しているように私には思えます:
Application.DoAction()
私はアプリケーションで、xmlから2000から3000のアイテムに関連する詳細をロードする必要があり、実装されたプロセスがアイテムを1つずつ読み取り、プロセスをハングアップさせていることを経験しました。ループで上記の行を使用すると、問題が解決しました。 UIはハングアップせず、ユーザーは他のフォームで作業できました。これが登場しましたprogressbar is now as background process
(ある程度まで)私には。
それが役に立てば幸い!
プログレスバーをバックグラウンドスレッドにしたいというあなたの願望は理解していますが、これはできないと確信しています。アプリケーションのビジュアルコンポーネントを更新する必要があるため、UIをプライマリスレッドにする必要があります。メニュー項目を含む、フォーム上のすべてのコントロールを無効にするのは簡単です。
このプロセスを提案させてください:
記載されているプログレスバーを使用してフォームを表示します。
他のフォームを表示する場合は、フォームに直接あるすべての子コントロールを無効にします。コントロールによっては、子コントロールをウォークスルーして無効にする必要がある場合があります。
データベースの更新を実行するコードで、プログレスバーの値を必要な値に更新します。値を更新したら、プログレスバーのrefreshメソッドを呼び出します。これにより、プログレスバーが強制的に正しくペイントされます。
更新が完了したら、プログレスバーを非表示にし、無効にしたすべてのフォームのすべてのコントロールを再度有効にします。
これにより、バックグラウンドスレッドで実行されているプログレスバーの外観が得られますが、アプリケーションは必要に応じてメインスレッドをブロックできます。
これはテストされていませんが、BGWに情報を供給するためにこのようなことをしたことを思い出します。これにより、バックグラウンドワーカーのコンテンツが更新されます。
まず、次の変数を使用してクラス(つまり、ProgExample)を作成し、それをグローバルオブジェクトとして配置します。
Dim ProgValue as Integer;
Dim ProgMax as Integer;
次に、クラスをバックグラウンドワーカーにフィードします。
BackgroundWorker1.RunWorkerAsync(_ProgExample)
それを読んで、中に入れてください:
Dim BGWProgExample as ProgExample = DirectCast(e.Argument, ProgExample),
バックグラウンドワーカーで次のことを行います。
BGWProgressBar.Maximum = BGWProgExample.ProgMax
while BGWProgExample.ProgValue <> BGWProgExample.ProgMax
BGWProgressBar.Value = BGWProgExample.ProgValue
したがって、何かを行ったら、_ProgExample.ProgValueを更新するだけです。 ProgValueを引数として渡すだけで、クラスなしでこれを実行しようとしないでください。つまり、ProgValueのコピーを現在の状態で送信し、ProgValueを更新しても変更されないことを意味します。そして、これで何も起こらない場合は、Application.DoEventsやApplication.DoActionをこれと一緒に試してください。
質問がわからないかもしれませんが、本当に簡単ではありませんか?
For i = ProgressBar1.Minimum To ProgressBar1.Maximum
ProgressBar1.Value = i
ProgressBar1.Update()
System.Threading.Thread.Sleep(25)
Next
プログレスバーの「更新」がそのトリックを行います。あなたのコードは「ブロック」しますが(私にはわかりませんが、「アプリケーションが応答しない」ことが望ましい理由はわかりません)、プログレスバーはupdatedを取得します。
ところで:Windows Vista/7(プログレスバーアニメーション)の場合、これをチェックするかもしれません: プログレスバーはWindowsフォームでは遅い