10

外部ソースから大量のデータを読み取るループがあります。このプロセスには約20秒かかりますが、進行状況をユーザーに表示したいと思います。派手なプログレスバーは必要ないので、「ステップ1/1000」というラベルに進行状況をプロットしてから、「ステップ2/1000」などに変更することにしました。

私のコードは次のようになります。

// "count" is the number of steps in the loop, 
// I receive it in previous code

String countLabel = "/"+count.ToString();

for (i = 0; i < count; i++)
{
    ... do analysis ...
    labelProgress.Content = "Step "+i.ToString()+countLabel
}

ただし、その分析中、画面は「スタック」しており、進行状況は進行中として表示されません。私はC++での過去からこの動作を理解しています。おそらく、ループからの通知を受信するプログレスバーを表示する別のスレッド、または何らかの形式の再描画/更新、またはウィンドウ/アプリにメッセージキューの処理を強制するスレッドがあります。

C#でそれを行う正しい方法は何ですか?私はラベルに縛られていないので、このラベルの代わりに使用できる単純なプログレスバーのポップアップ画面があれば、それも素晴らしいでしょう...

ありがとう

4

3 に答える 3

13

作業をBackgroundWorkerに移動し、 ReportProgressメソッドを使用します。

for (i = 0; i < count; i++)
{
    ... do analysis ...
    worker.ReportProgress((100 * i) / count);
}

private void MyWorker_ProgressChanged(object sender,
    ProgressChangedEventArgs e)
{
    taskProgressBar.Value = Math.Min(e.ProgressPercentage, 100);
}
于 2009-07-28T14:54:15.800 に答える
3
    //Create a Delegate to update your status button
    delegate void StringParameterDelegate(string value);
    String countLabel = "/" + count.ToString();
    //When your button is clicked to process the loops, start a thread for process the loops
    public void StartProcessingButtonClick(object sender, EventArgs e)
    {
        Thread queryRunningThread = new Thread(new ThreadStart(ProcessLoop));
        queryRunningThread.Name = "ProcessLoop";
        queryRunningThread.IsBackground = true;
        queryRunningThread.Start();
    }

    private void ProcessLoop()
    {
        for (i = 0; i < count; i++)
        {
            ... do analysis ...
            UpdateProgressLabel("Step "+i.ToString()+countLabel);
        }
    }

    void UpdateProgressLabel(string value)
    {
        if (InvokeRequired)
        {
            // We're not in the UI thread, so we need to call BeginInvoke
            BeginInvoke(new StringParameterDelegate(UpdateProgressLabel), new object[] { value });
            return;
        }
        // Must be on the UI thread if we've got this far
        labelProgress.Content = value;
    }
于 2009-07-28T15:02:50.997 に答える
2

現在のスレッドの優先度が、最終的にラベルを設定する UI スレッドよりも高いため、UI は更新されません ;)。したがって、スレッドが処理を完了するまで、最終的にラベルが更新されます。

幸運なことに、すべての WPF コントロールには Dispatcher プロパティがあり、別の優先順位で新しいスレッドを起動できます。

labelProgress.Dispatcher.Invoke(DispatcherPriority.Background,
                    () => labelProgress.Content = string.Format("Step {0}{1}", i, countLabel));

これにより、バックグラウンドでスレッドが起動され、仕事が完了します! 他のDispatcherPriorityオプションを試すこともできます

PSまた、匿名メソッドを追加し、文字列の解析を多少修正する自由を取りました..気にしないでください..

于 2009-07-28T14:55:13.990 に答える