7

ライブラリで特定の操作を実行するクラスを作成しています。しかし、この操作は面倒なので、WinForms アプリケーションで使用して進行状況を報告できるように、そのクラス内のメソッドの進行状況を確認できるようにしたいと考えています。

クラスを WinForms アプリケーションの別のスレッドで実行する予定で、そのクラスを WinForms アプリケーションの懸念事項から切り離したいのですが、それが行うこと以外の特定のものにクラスをバインドしたくありません。

ライブラリ クラスに進捗レポート メカニズムを実装する最良の方法は何ですか?

クラスに進行状況変数を何らかの形で用意し、WinForms アプリケーションにイベント リスナーを追加するのは良い考えでしょうか? もしそうなら、どうすればそれを行うことができますか?

編集:以前にクラスを使用したことがありBackgroundWorkerますが、私の問題は、ライブラリ クラスをマルチスレッド操作に関係させたくないことです。ReportProgressそのため、ライブラリ クラスで呼び出したくありません。現在の進行状況を含むクラスに (おそらく) 変数が必要であり、UI スレッドに何らかの形で "サブスクライブ" させたいと考えています。それが良い設計方法かどうかはわかりません。

4

2 に答える 2

4

BackgroundWorkerクラスを調べます。進行状況レポートのためにスレッド間の自動マーシャリングをサポートし、この種のサポートのための非常に単純なイベント モデルを備えています。

編集:BackgroundWorkerを直接使用するというあなたの立場を考えると、あなたができることは単純なラッパーを作成することです:

// Error checking elided for expository purposes.
public interface IProgressReporter 
{
    void ReportProgress(int progress, object status);
}

public class BackgroundWorkerProgressReporter : IProgressReporter
{
    private BackgroundWorker _worker;
    public BackgroundWorkerProgressReporter(BackgroundWorker worker)
    {
        _worker = worker;
    }

    public void ReportProgress(int progress, object status)
    {
        _worker.ReportProgress(progress, status);
    }
}

次に、進行状況を報告するクラスのコンストラクターを変更 (またはプロパティを追加) して、IProgressReporter を受け入れるようにします。これは依存性注入の一種であり、スレッド ライブラリへの特定の依存性を回避しながら、オブジェクトが進行状況を報告できるようにする必要があります。

于 2012-12-05T04:42:50.620 に答える
1

ここでは、2つの異なる方法を実行できます。正しい方向に向けるために、両方のオプションを以下に投稿します

別のスレッドでこれを行ってから、そのスレッドから UI スレッドを更新する必要があります。UI スレッドでこの作業を実行することにより、以降の処理をブロックしています。

このコードを UI スレッドに移動できない場合は、いつでも を呼び出すことができますが、最初にこれらのオプションを検討することApplication.DoEvents強くお勧めします。

2番目の代替案は、次のようにすることができます:

あるスレッドから別のスレッドにデータを取得する必要があります。これにはいくつかの方法があります...

まず、「バックグラウンド」スレッドは、進行中に変化するある種の「CurrentStatus」文字列変数を更新できます。次に、フォームにタイマーを配置して、CurrentStatus 変数を取得し、それでラベルを更新することができます。

次に、ラベル コントロールの InvokeRequired プロパティを使用して、デリゲートを使用して、バックグラウンド スレッドから UI スレッドへの操作を呼び出すだけです。だから例えば…

private delegate void UpdateStatusDelegate(string status);
private void UpdateStatus(string status)
{
    if (this.label1.InvokeRequired)
    {
        this.Invoke(new UpdateStatusDelegate(this.UpdateStatus), new object[] { status });
        return;
    }

    this.label1.Text = status;
}

その UpdateStatus() メソッドを任意のスレッド (UI またはバックグラウンド) から呼び出すことができ、メイン UI スレッドで操作を呼び出す必要があるかどうかを検出します (必要な場合は実行します)。

編集:実際にスレッドを設定するには、次のようにします。

    private void StartProcessing()
    {
        System.Threading.Thread procThread = new System.Threading.Thread(this.Process);

        procThread.Start();
    }

    private void Process() // this is the actual method of the thread
    {
        foreach (System.IO.FileInfo f in dir.GetFiles("*.txt"))
        {
            // Do processing
            // Show progress bar
            // Update Label on Form, "f.Name is done processing, now processing..."
            UpdateStatus("Processing " + f.Name + "...");                
        }
    }

次に、ユーザーが「GO」ボタンをクリックすると、単に StartProcessing() を呼び出します。

于 2012-12-05T04:42:42.990 に答える