9

アプリケーションが起動し、アップグレードされたばかりのときに、ローカル データベースの更新 (sqlite) を実行しています。

それはそのようなものです: ユーザーが私のアプリを起動し、次に私がアップグレード プロセスを開始します。このアップグレード プロセス中に、継続的な進行状況バーを持つフォームを表示しています。このフォームは、アップグレード プロセスが完了すると閉じ、ユーザーはアプリケーションの使用を開始できます。

ただし、アップグレード プロセスは非常に集中的なため、進行状況バーはアニメーション化されません。

私の古い VB6 バージョンでは、フォームが 1 つありプログレスバーを表示する ActiveX-Exe を使用していました。これが私の「バックグラウンド ワーカー」でした。

VB.NET で同じアプローチを使用できるかどうかはわかりません。

バックグラウンドワーカーで作業を行う例は見たことがありますが、プログレスバー自体がバックグラウンドワーカーである例は見たことがありません。

データベースのアップグレードはブロックする必要があります。データベースのアップグレードが完了する前に、ユーザーはアプリケーションを使用できない可能性があります。これは、プログレスバーのみが「アウト プロセス」であり、アップグレードは対象外であることを意味します。

どうもありがとうございました!

4

6 に答える 6

12

最初にこれを読んでください: Application.DoEvents() の使用

したがって、上記の回答を読んだ後は、二度と DoEvents を使用することはなく、DoEvents がなければ (および/または ProgressBar を無効にして Paint イベントが発生する)、「アップグレード プロセスが非常に集中しているため、プログレスバーはアニメーション化されません」

したがって、クトゥルフのコメント-「プログレスバーでダイアログを作成し、そのダイアログをモーダルにして、バックグラウンドワーカーで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 です。これは、データベースの更新にかかる時間を予測するのは非常に難しいため、用途に適しています。

ここに画像の説明を入力

于 2012-11-21T05:05:22.130 に答える
3

あなたの要件から、あなたが探しているように私には思えます:

Application.DoAction()

私はアプリケーションで、xmlから2000から3000のアイテムに関連する詳細をロードする必要があり、実装されたプロセスがプロセスをハングアップするアイテムを1つずつ読み取っていたことを経験しました。ループで上記の行を使用すると、問題が解決しました。UIはハングアップせず、ユーザーは他のフォームで作業できました。これはprogressbar is now as background process(ある程度まで)私に現れました。

それが役に立てば幸い!

于 2012-11-15T07:06:57.790 に答える
3

プログレスバーをバックグラウンド スレッドにしたいというご要望は承知しておりますが、それができないことは確かです。アプリケーションのビジュアル コンポーネントを更新する必要があるため、UI をプライマリ スレッドにする必要があります。メニュー項目を含む、フォーム上のすべてのコントロールを無効にするのは簡単です。

このプロセスを提案させてください:

  1. 言及されたプログレスバーでフォームを表示します。

  2. 他のフォームを表示する場合は、フォームに直接あるすべての子コントロールを無効にします。コントロールによっては、子コントロールを無効にするためにウォークスルーする必要がある場合があります。

  3. データベースの更新を実行するコードで、プログレスバーの値を任意の値に更新します。値を更新したら、プログレスバーの refresh メソッドを呼び出します。これにより、プログレスバーが正しく描画されます。

  4. 更新が完了したら、進行状況バーを非表示にし、無効にしたすべてのフォームのすべてのコントロールを再度有効にします。

これにより、バックグラウンド スレッドで実行されているプログレスバーの外観が得られますが、アプリケーションは必要に応じてメイン スレッドをブロックできます。

于 2012-11-20T00:06:13.767 に答える
1

質問の意味がよくわからないかもしれませんが、とても簡単ではありませんか?

For i = ProgressBar1.Minimum To ProgressBar1.Maximum
        ProgressBar1.Value = i
        ProgressBar1.Update()
        System.Threading.Thread.Sleep(25)
    Next

プログレスバーの「更新」がそのトリックを行います。あなたのコードは「ブロック」します(「アプリケーションが応答しない」ことが望ましい理由はわかりませんが)が、プログレスバーは更新されます。

ところで: Windows Vista/7 (プログレスバー アニメーション) の場合は、これを確認できます: ProgressBar is slow in Windows Forms

于 2012-11-15T10:31:26.117 に答える
1

これはテストされていませんが、情報を 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 を試してください。

于 2012-11-15T07:43:50.093 に答える
-1

バックグラウンド ワーカーでイベントを発生させてから、UI スレッドの進行状況バーを更新できます。クラスでイベントを発生させ、フォームで処理できます。それらが発生したら、バックグラウンド ワーカーで reportprogress() を呼び出すことができます。

いくつかの詳細情報:

メインスレッドをブロックせずに実行時間の長い UI 変更を実行する

于 2012-11-03T10:26:14.270 に答える