9

プログレスバーを使用して、プロセスの進行状況をユーザーに示しています。17のステップがあり、天気に応じて5秒から2〜3分かかる場合があります(データベース)

XPではこれに問題はなく、プログレスバーは正常に機能しましたが、ビスタでテストしたところ、もはやそうではないことがわかりました。

例:5秒近くかかると、完了したために消えるまでの3分の1になる可能性があります。進捗状況は17の17ですが、表示されません。これは、Vistaがプログレスバーに課すアニメーションと、アニメーションが十分に速く終了できないためだと思います。

誰かが私がこれを修正する方法を知っていますか?

コードは次のとおりです。

これはプログレスバーを更新する部分であり、待機はプログレスバーのあるフォームです。

        int progress = 1;
        //1 Cash Receipt Items
        waiting.setProgress(progress, 18, progress, "Cash Receipt Items");
        tblCashReceiptsApplyToTableAdapter1.Fill(rentalEaseDataSet1.tblCashReceiptsApplyTo);
        progress++;
        //2 Cash Receipts
        waiting.setProgress(progress, "Cash Receipts");
        tblCashReceiptsTableAdapter1.Fill(rentalEaseDataSet1.tblCashReceipts);
        progress++;
        //3 Checkbook Codes
        waiting.setProgress(progress, "Checkbook Codes");
        tblCheckbookCodeTableAdapter1.Fill(rentalEaseDataSet1.tblCheckbookCode);
        progress++;
        //4 Checkbook Entries
        waiting.setProgress(progress, "Checkbook Entries");
        tblCheckbookEntryTableAdapter1.Fill(rentalEaseDataSet1.tblCheckbookEntry);
        progress++;
        //5 Checkbooks
        waiting.setProgress(progress, "Checkbooks");
        tblCheckbookTableAdapter1.Fill(rentalEaseDataSet1.tblCheckbook);
        progress++;
        //6 Companies
        waiting.setProgress(progress, "Companies");
        tblCompanyTableAdapter1.Fill(rentalEaseDataSet1.tblCompany);
        progress++;
        //7 Expenses
        waiting.setProgress(progress, "Expenses");
        tblExpenseTableAdapter1.Fill(rentalEaseDataSet1.tblExpense);
        progress++;
        //8 Incomes
        waiting.setProgress(progress, "Incomes");
        tblIncomeTableAdapter1.Fill(rentalEaseDataSet1.tblIncome);
        progress++;
        //9 Properties
        waiting.setProgress(progress, "Properties");
        tblPropertyTableAdapter1.Fill(rentalEaseDataSet1.tblProperty);
        progress++;
        //10 Rental Units
        waiting.setProgress(progress, "Rental Units");
        tblRentalUnitTableAdapter1.Fill(rentalEaseDataSet1.tblRentalUnit);
        progress++;
        //11 Tenant Status Values
        waiting.setProgress(progress, "Tenant Status Values");
        tblTenantStatusTableAdapter1.Fill(rentalEaseDataSet1.tblTenantStatus);
        progress++;
        //12 Tenants
        waiting.setProgress(progress, "Tenants");
        tblTenantTableAdapter1.Fill(rentalEaseDataSet1.tblTenant);
        progress++;
        //13 Tenant Transaction Codes
        waiting.setProgress(progress, "Tenant Transaction Codes");
        tblTenantTransCodeTableAdapter1.Fill(rentalEaseDataSet1.tblTenantTransCode);
        progress++;
        //14 Transactions
        waiting.setProgress(progress, "Transactions");
        tblTransactionTableAdapter1.Fill(rentalEaseDataSet1.tblTransaction);
        progress++;
        //15 Vendors
        waiting.setProgress(progress, "Vendors");
        tblVendorTableAdapter1.Fill(rentalEaseDataSet1.tblVendor);
        progress++;
        //16 Work Order Categories
        waiting.setProgress(progress, "Work Order Categories");
        tblWorkOrderCategoryTableAdapter1.Fill(rentalEaseDataSet1.tblWorkOrderCategory);
        progress++;
        //17 Work Orders
        waiting.setProgress(progress, "Work Orders");
        tblWorkOrderTableAdapter1.Fill(rentalEaseDataSet1.tblWorkOrder);
        progress++;
        //18 Stored procs
        waiting.setProgress(progress, "Stored Procedures");
        getAllCheckbookBalancesTableAdapter1.Fill(rentalEaseDataSet1.GetAllCheckbookBalances);
        getAllTenantBalancesTableAdapter1.Fill(rentalEaseDataSet1.GetAllTenantBalances);
        //getCheckbookBalanceTableAdapter1;
        //getTenantBalanceTableAdapter1;
        getTenantStatusID_CurrentTableAdapter1.Fill(rentalEaseDataSet1.GetTenantStatusID_Current);
        getTenantStatusID_FutureTableAdapter1.Fill(rentalEaseDataSet1.GetTenantStatusID_Future);
        getTenantStatusID_PastTableAdapter1.Fill(rentalEaseDataSet1.GetTenantStatusID_Past);
        selectVacantRentalUnitsByIDTableAdapter1.Fill(rentalEaseDataSet1.SelectVacantRentalUnitsByID);
        getRentBasedBalancesTableAdapter1.Fill(rentalEaseDataSet1.GetRentBasedBalances);
        getAgingBalanceTableAdapter2.Fill(rentalEaseDataSet1.GetAgingBalance);


        waiting.Close();

待機中のフォームは次のとおりです。

public partial class PleaseWaitDialog : Form {
    public PleaseWaitDialog() {
        CheckForIllegalCrossThreadCalls = false;
        InitializeComponent();
    }

    public void setProgress(int current, int max, int min, string loadItem) {
        Debug.Assert(min <= max, "Minimum is bigger than the maximum!");
        Debug.Assert(current >= min, "The current progress is less than the minimum progress!");
        Debug.Assert(current <= max, "The progress is greater than the maximum progress!");

        prgLoad.Minimum = min;
        prgLoad.Maximum = max;
        prgLoad.Value = current;
        lblLoadItem.Text = loadItem;
    }

    public void setProgress(int current, string loadItem) {
        this.setProgress(current, prgLoad.Maximum, prgLoad.Minimum, loadItem);
    }
}
4

9 に答える 9

37

Vistaでは、プログレスバーを更新するときにアニメーション効果が導入されました。これは、前の位置から新しく設定された位置にスムーズにスクロールしようとするため、コントロールの更新に厄介なタイムラグが生じます。ラグは、プログレスバーを大きな増分でジャンプするときに最も顕著になります。たとえば、1回のジャンプで25%から50%になります。

別のポスターが指摘しているように、プログレスバーのVistaテーマを無効にすると、XPプログレスバーの動作を模倣できます。

別の回避策を見つけました。プログレスバーを逆に設定すると、すぐにこの場所にペイントされます。したがって、25%から50%にジャンプしたい場合は、(明らかにハックっぽい)ロジックを使用します。

progressbar.Value = 50;
progressbar.Value = 49;
progressbar.Value = 50;

私は知っています、私は知っています-それはばかげたハックです-しかしそれは機能します!

于 2009-07-31T18:35:48.460 に答える
11

この全体的な混乱の理由は、VistaとW7によって導入された補間アニメーション効果です。スレッドブロッキングの問題とはまったく関係ありません。setProgress()を呼び出すか、Valueプロパティを直接設定すると、アニメーション効果が発生します。これをチートする方法を説明します。

固定値に従って最大値を設定するハックを思いついた。最大プロパティは効果をトリガーしないため、即座に応答して進行状況を自由に移動できます。

実際に表示される進行状況は、ProgressBar.Value/ProgressBar.Maximumで指定されることに注意してください。これを念頭に置いて、以下の例では、進行状況を0から100に移動し、iによって表されます。

ProgressBar works like this:  
progress = value / maximum

therefore:
maximum = value / progress

必要なスケーリング係数をいくつか追加しました。自明である必要があります。

progressBar1.Maximum *= 100;
progressBar1.Value = progressBar1.Maximum / 100;
for (int i = 1; i < 100; i++)
{
    progressBar1.Maximum = (int)((double)progressBar1.Value / (double)(i + 1) * 100);
    Thread.Sleep(20);
}
于 2009-11-24T09:09:04.900 に答える
3

UIスレッドですべてを実行しているため、メッセージポンプを解放していないようです。BackgroundWorkerイベントのようなスモーシングを使ってみProgressChangedましたか?例については、 MSDNを参照してください。

BackgroundWorkerInvoke外部データをロードするのに理想的ですが、UIスレッドに戻るまで(または/を使用BeginInvokeしてUIスレッドに作業をプッシュするまで)データバインディングなどを実行しないように注意してください。

于 2009-06-10T18:14:09.973 に答える
2

別のスレッドに存在しているように見えるwaiting.setProgess()ので、メソッドの呼び出しを呼び出してみてください。これは、古典的なクロススレッド呼び出しになります(コンパイラーは、彼に許可すると警告します)。waiting

使用するのは少し不器用なのでControl.Invoke、私は通常、ラムダ式を渡すことができる拡張メソッドを使用します。

waiting.ThreadSafeInvoke(() => waiting.setProgress(...));

// also see http://stackoverflow.com/questions/788828/invoke-from-different-thread
public static class ControlExtension
{
    public static void ThreadSafeInvoke(this Control control, MethodInvoker method)
    {
        if (control != null)
        {
            if (control.InvokeRequired)
            {
                control.Invoke(method);
            }
            else
            {
                method.Invoke();
            }
        }
    }
}
于 2009-06-10T19:34:19.903 に答える
1

ProgressBarコントロールの拡張メソッドとして、MarkLansdownの優れた回答を使用します。

public static void ValueFast(this ProgressBar progressBar, int value)
{
    progressBar.Value = value;

    if (value > 0)    // prevent ArgumentException error on value = 0
    {
        progressBar.Value = value - 1;
        progressBar.Value = value;
    }

}

または、次のようにして、ProgressBar値プロパティを3回ではなく2回だけ設定することもできます。

public static void ValueFast(this ProgressBar progressBar, int value)
{
    if (value < 100)    // prevent ArgumentException error on value = 100
    {
        progressBar.Value = value + 1;    // set the value +1
    }

    progressBar.Value = value;    // set the actual value

}

拡張メソッドを使用して、ProgressBarコントロールで呼び出すだけです。

this.progressBar.ValueFast(50);

本当に必要な場合は、現在のWindows環境を確認し、Windows XPのプログレスバーには遅い進行状況のアニメーションがないため、WindowsVista+のコードのハックセクションのみを実行することもできます。

于 2013-12-17T17:54:52.080 に答える
1

Silas Hansenの答えを拡張すると、これは毎回完璧な結果をもたらすようです。

protected void UpdateProgressBar(ProgressBar prb, Int64 value, Int64 max)
{
    if (max < 1)
        max = 1;
    if (value > max)
        value = max;
    Int32 finalmax = 1;
    Int32 finalvalue = 0;
    if (value > 0)
    {
        if (max > 0x8000)
        {
            // to avoid overflow when max*max exceeds Int32.MaxValue.
            // 0x8000 is a safe value a bit below the actual square root of Int32.MaxValue
            Int64 progressDivideValue = 1;
            while ((max / progressDivideValue) > 0x8000)
                progressDivideValue *= 0x10;
            finalmax = (Int32)(max / progressDivideValue);
            finalvalue = (Int32)(value / progressDivideValue);
        }
        else
        {
            // Upscale values to increase precision, since this is all integer division
            // Again, this can never exceed 0x8000.
            Int64 progressMultiplyValue = 1;
            while ((max * progressMultiplyValue) < 0x800)
                progressMultiplyValue *= 0x10;
            finalmax = (Int32)(max * progressMultiplyValue);
            finalvalue = (Int32)(value * progressMultiplyValue);
        }
    }
    if (finalvalue <= 0)
    {
        prb.Maximum = (Int32)Math.Min(Int32.MaxValue, max);
        prb.Value = 0;
    }
    else
    {
        // hacky mess, but it works...
        // Will pretty much empty the bar for a split second, but this is normally never visible.
        prb.Maximum = finalmax * finalmax;
        // Makes sure the value will DEcrease in the last operation, to ensure the animation is skipped.
        prb.Value = Math.Min(prb.Maximum, (finalmax + 1));
        // Sets the final values.
        prb.Maximum = (finalmax * finalmax) / finalvalue;
        prb.Value = finalmax;
    }
}
于 2015-08-07T07:51:14.910 に答える
0

初め。CheckForIllegalCrossThreadCallsオプションをオフにすることは決してありません。

2番。進行状況を更新した後、Refresh()を追加します。別のスレッドで作業しているからといって、GUIスレッドが更新に取り掛かるわけではありません。

于 2009-06-10T19:07:41.220 に答える
0

私も同じ問題を抱えてる。複数のプログレスバーがあるフォームがあります(上のプログレスバーはたとえばファイルx / n、下のプログレスバーはタスクy / mです)上のプログレスバーはタイムリーに更新されませんが下のプログレスバーはプログラムで更新されます。 、更新またはスリープはそれを修正しません。面白いことに、下部のプログレスバーとその他のコンポーネント(経過時間のテキスト)が正常に更新されます。これは純粋にVista+テーマの問題です(以前に提案されたようなアニメーション、クラシックテーマのXPまたはVistaは正常に機能します。上部のプログレスバーが100に移動した後にメッセージボックスを表示すると(プログラムで、視覚的にではなく)、最初にメッセージボックスが表示されます。その後、進捗状況が完了します

SetWindowTheme(ProgressBar.Handle、''、''); Vista Aeroの作品でプログレスバーアニメーションを無効にするで説明したように (ただし、現在は古いスタイルのプログレスバーがあります)

于 2009-06-26T14:09:21.480 に答える
0

Application.DoEvents();を試しましたか??

于 2015-11-12T12:15:00.253 に答える