2

深刻なスワップ/置換操作のために、大きなTxtドキュメントをWPFアプリに読み込んでいます。ファイルは実際には3DSTPモデルであるため、かなり大きいですが、このプロジェクトの生のテキストとして使用しています。ファイルはリストに読み込まれ、何度も開く必要がなくなり、比較が容易になります。

とにかく、ファイルサイズによっては計算に少し時間がかかることがあるため、リストボックスに行が追加されるときにリストボックスを動的にスクロールさせようとしています。これは、コンソールウィンドウで、ユーザーが何かが起こっていることを確認できるようにするためです。また、合計行数が読み取られるときにカウントするプログレスバーを追加しました。

ただし、作業が進むにつれて、プログレスバーもListBoxも更新されないようです。最終的な出力は、完了したリストボックスに表示されるだけで、進行状況バーは同時に0から最大になります。

これが私がしていることの要点であり、かなり単純です。

   foreach (string Line in OriginalSTPFile.Lines)
   {
       string NewLine = EvaluateString(Line);  //string the modified to whatever here
       pBar.Value++;   //increment progressbar

       OutputWindow.Items.Add(NewLine);  //add line to the ListBox
   }

進行状況の変化に応じて、リストボックスの進行状況バーをリアルタイムで更新したいだけです。私は使ってみました:

Dispatcher.BeginInvoke(new Action(() => OutputWindow.Items.Add(NewLine));

しかし、同じ結果が得られました。ここでマルチスレッドのより複雑な方法が必要ですか?クロススレッド例外も生成していなかったので、最初の方法が機能すると思いました。

4

2 に答える 2

1

Dispatcher.BeginInvokeは、Dispatcherのスレッドでメソッドを呼び出すように通知します。ただし、メインスレッドがロックされて作業を行っている間は発生しないため、これは基本的に投稿メッセージのようなものです。また、メインスレッドが再び使用可能になるまで、値を変更してもUIは視覚的に更新されません。

バックグラウンドスレッドで作業を実行する必要があります。

ただし、UIを更新するには、UIのメインスレッドで更新する必要があります。これはWPFの制限です。これが、ディスパッチャに誘導された理由です。誰かがあなたの作品がすでにバックグラウンドスレッドにあると思っていたと思います。

スレッドを作成するには、Thread.Start実行するデリゲートを渡すことを使用します。匿名のデリゲートまたはラムダを使用する場合、スタック上の変数を参照できますが、デリゲートが終了するまで変数が存続することに注意してください。これが、匿名デリゲートで参照変数を使用できない理由です。

Backgroundworkerは、特殊なタイプのバックグラウンドスレッドです。ワーカースレッドの期待の一部(完了の通知と進行状況の更新)を自動化しますが、それがなくても同じ結果を得ることができます。

スレッドの処理中にUIを更新するには、そのスレッドがメインUIスレッドにアクセスできるようにする必要があります。これを行うには、ディスパッチャーを渡すか、匿名デリゲートの外部からディスパッチャーを参照するか、ディスパッチャーを含むオブジェクトを使用します。任意のスレッドの任意のオブジェクトからいつでも値を読み取ることができるため、別のスレッドのUIElementからディスパッチャーにアクセスすることは問題ありません。

UIを更新するにDispatcher.BeginInvokeは、実行する作業を伴うデリゲートを使用して呼び出します。

これが全体的なスキームの疑似コードです

class TestProgress
{
    ProgressBar _ProgressBar;

    void DoWork()
    {
        var worker = (Action)(() =>
        {
            int progress = 0;
            // do stuff, delta is change in progress
            progress += delta;
            _ProgressBar.Dispatcher.BeginInvoke((Action)(() =>
            {
                _ProgressBar.Value = progress;
            }));
        });
        Thread.Start(worker);
    }
}
于 2013-02-13T20:46:36.213 に答える
1

この記事では、必要なすべてのコードを提供します。

プログレスバー付きのバックグラウンドワーカー

何をすべきか、どの要素を使用すべきかを非常によく説明しています。

于 2013-02-13T20:15:55.980 に答える