2

時間のかかるタスクを実行するためにBackgroundWorkerスレッドを実行しています。時間のかかるタスクは別のクラスにあります。BackgroundWorkerで実行されているこの別のクラスで行われている進行状況をメインForm1クラスに戻す必要があります。これにどうアプローチするかわかりません。提案を提供してください。前もって感謝します。

    **// Main Form1 UI Class**    

    public void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
    {
        //e.Argument always contains whatever was sent to the background worker
        // in RunWorkerAsync. We can simply cast it to its original type.
        DataSet ds = e.Argument as DataSet;
        this.createje.ProcessData(this.ds);
    }

    private void backgroundWorker2_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        this.progressBar1.Minimum = 0;
        this.progressBar1.Maximum = CreateJE.max;
        this.progressBar1.Value = e.Recno;
    }

    **//Other Class called CreateJE**

    public void ProcessData(DataSet ds)
    {
        //Do time consuming task...
     for (int i = 1; i <= 10; i++)
        {
            if (worker.CancellationPending == true)
            {
                e.Cancel = true;
                break;
            }
            else
            {
                // Perform a time consuming operation and report progress.
                System.Threading.Thread.Sleep(500);

                **//How do I report progress back to the Main UI?** 
                //worker.ReportProgress(i * 10);
            }
        }
    }
4

2 に答える 2

4

最もクリーンで最も拡張性の高い解決策は、ProcessData()メソッドでイベントを発生させ、BackgroundWorkerがリッスンしていることです。この方法は、呼び出し元として aProcessData()を持つことに依存しません。BackgroundWorker( をキャンセルする方法も必要ですProcessData())。必要に応じて再利用することもできProgressChangedEventArgsます。例(テストされていませんが、アイデアはわかりますか?):

partial class Form1 { 
    public void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e) {
        //e.Argument always contains whatever was sent to the background worker 
        // in RunWorkerAsync. We can simply cast it to its original type.
        DataSet ds = (DataSet)e.Argument;
        var bgw = (BackgroundWorker)sender;

        var eh = new ProgressChangedEventHandler((o,a) => bgw.ReportProgress(a.ProgressPercentage));
        createje.ProgressChanged += eh;
        this.createje.ProcessData(this.ds));
        createje.ProgressChanged -= eh; //necessary to stop listening
    }

    private void backgroundWorker2_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        this.progressBar1.Minimum = 0;
        this.progressBar1.Maximum = CreateJE.max;
        this.progressBar1.Value = e.ProgressPercentage;
    }

}

partial class CreateJE { 

    public event ProgressChangedEventHandler ProgressChanged; 
    protected virtual void OnProgressChanged(ProgressChangedEventArgs e)
    { 
        var hand = ProgressChanged; 
        if(hand != null) hand(this, e);
    }

    public void ProcessData(DataSet ds)
    {
        for(int i = 1; i <= 10; i++)
        {
            // Perform a time consuming operation and report progress.
            System.Threading.Thread.Sleep(500);

            var e = new ProgressChangedEventArgs(i * 10, null);
        }
    }

}

手っ取り早い方法はBackgroundWorker、 をパラメータとしてに渡すことProcessData()です。これはかなり見苦しいですが、BackgroundWorkers のみを使用する必要がありBackgroundWorker、ReportProgress の戻り値をある場所 (メイン フォーム クラス) で定義し、別の場所 (CreateJE クラス) で ReportProgress の戻り値を定義する必要があります。

また、タイマーを使用して X ミリ秒ごとに進行状況を報告し、CreateJE オブジェクトにその進行状況を照会することもできます。これは、コードの残りの部分と一致しているようです。これに伴うハングアップは、CreateJE クラスがマルチスレッド対応でなくなることです。

于 2012-08-13T15:01:31.277 に答える
1

delegate最も迅速で簡単なオプションは、進行状況を報告するin クラスを宣言し、これを のメソッドにCreateJEフックすることです。ReportProgressBackgroundWorker

class CreateJE
{
    public Action<int> ReportProgressDelegate{get;set;}

    public void ProcessData(DataSet ds)
    {
        for(int i = 0; i < 10; i++)
        {
            Thread.Sleep(500);
            ReportProgress(i*10);
        }
    }

    private void ReportProgress(int percent)
    {
        if(ReportProgressDelegate != null)
            ReportProgressDelegate(percent);
    }
}

ReportProgressDelegateフォームで、インスタンスのプロパティを初期化します (this.createjeフォームのフィールドを参照すると想定しているためOnLoad、初期化を行うのに適した場所のようです)。

protected override void OnLoad(EventArgs e)
{
    this.creatje.ReportProgressDelegate = worker.ReportProgress;
}

その後、すでに持っているイベント ハンドラー (backgroundWorker2_DoWorkおよびbackgroundWorker2_DoWork) を使用できます。

PS:プロパティでも同じアプローチを使用する必要がありworker.CancellationPendingます。

于 2012-08-13T15:25:44.340 に答える