0
    // sample 1 use BackgroundWorker, it works fine
    private BackgroundWorker workerPorcee = new BackgroundWorker();
    private void button1_Click(object sender, EventArgs e)
    {
        workerPorcee.DoWork += new DoWorkEventHandler(workerPorcee_DoWork);
        workerPorcee.ProgressChanged += new ProgressChangedEventHandler(workerPorcee_ProgressChanged);
        workerPorcee.RunWorkerCompleted += new RunWorkerCompletedEventHandler(workerPorcee_RunWorkerCompleted);
        workerPorcee.WorkerReportsProgress = true;
        workerPorcee.RunWorkerAsync();
    }
    void workerPorcee_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        this.progressBar1.Value = e.ProgressPercentage;
    }
    void workerPorcee_DoWork(object sender, DoWorkEventArgs e)
    {
        for (int i = 0; i < 100; i++)
        {
            workerPorcee.ReportProgress(i);
            Thread.Sleep(100);
        }
    }

    void workerPorcee_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        this.progressBar1.Value = 100;
    }

ワーカースレッドを実装しただけですが、例外が発生します。クロススレッド操作が無効です:作成されたスレッド以外のスレッドからアクセスされたコントロール'progressBar1'。

    // my worker thread
     private void button3_Click(object sender, EventArgs e)
    {
        Worker wk = new Worker();
        Thread thr = new Thread(new ThreadStart(wk.ProcessEvent));
        wk.ProgressChanged += new delCallback(wk_ProgressChanged);
        thr.Start();
    }        

    void wk_ProgressChanged(int percent)
    {
        this.progressBar1.Value = percent;
    //exception:Cross-thread operation not valid: Control 'progressBar1' accessed from a thread other than the thread it was created on.       

     }

     public delegate void delCallback(int percent);

public class Worker
{
    public event delCallback ProgressChanged;

    public void ProcessEvent()
    {
        for (int i = 0; i < 100; i++)
        {
            if (ProgressChanged != null)
            {
                this.ProgressChanged(i);
            }
            Thread.Sleep(100);
        }
    }
}

WinForm、プログレスバーの値を設定するためにワーカースレッドを使用したいのですが、失敗します。誰かが問題が何であるかを指摘するのを助けますか?BackgroundWorkerと同じように機能を実装するにはどうすればよいですか?

4

1 に答える 1

0

winFormsコントロールとのすべての対話が、コントロールを作成したメインスレッドで実行されるようにする必要があります。これは、例外が示していることです。これを行うには、Control.Invokeメソッドを使用する必要があります。これにより、UIを変更するメソッドの呼び出しが正しいスレッドで実行されるようになります。

したがって、コード例では、次のように変更する必要があります。

void wk_ProgressChanged(int percent)
{
    if(this.progressBar1.InvokeRequired)
    {
        this.progressBar1.Invoke(wk_ProgressChanged, new Object[] {percent});
    }
    else
    {
        this.progressBar1.Value = percent;
    }       
 }

最初の部分は、progressBar1コントロールの正しいスレッドでメソッド呼び出しが実行されているかどうかを確認します。別のスレッドを使用している場合は、Invokeを使用して同じメソッドを呼び出しますが、正しいスレッドを使用します。次に、Invokeはwk_ProgressChangedメソッドを呼び出しますが、今回はInvokeRequiredがfalseになり(UI更新を実行するために正しいスレッドで実行されているため)、progressBar1値が設定されます。

于 2012-06-28T22:18:07.347 に答える