0

いくつかのコンボボックスとグリッドビューを持つ winform があります。

最初に、行と列を使用してグリッドビューを作成し、データを入力していません。

ここに画像の説明を入力

グリッドへのデータの入力は、すべての行をループして列ヘッダーを読み取り、それに応じて各セルに異なる色とデータを適用する長時間実行タスクです。

私が達成しようとしているのは、フォーム ロード イベントで上記のようにグリッドをロードし、フォームがロードされた後にグリッドへのデータの入力を開始して、ユーザーが何が起こっているかを確認できるようにすることです。コンボボックスの値に応じてデータをロードするため、コンボボックスの値の変更にも同じことが当てはまります。

私が試したことは、このようなものです...

フォームの読み込みでメソッドを呼び出しています

 private void LoadForm()
        {                        
            DataBind(); // this will load the initial grid without cell data            

            this.BeginInvoke((MethodInvoker)this.LongRunningProcess1);

            this.BeginInvoke((MethodInvoker)this.LongRunningProcess2);

         }

しかし、それでも時間がかかり、レスポンシブ UI がありません。

私もこのようなことを試しましたが、運がありません....

            ThreadStart ts = LongRunningProcess1;
            Thread t1 = new Thread(ts);
            t1.Start();

また、バックグラウンド ワーカーを使用して実行時間の長い操作を完了すると、「クロス スレッド操作」の問題が発生します。

 private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
                LongRunningProcess1();
                LongRunningProcess2();           
        }

これを機能させるための助けに感謝します..

ありがとう

アップデート

私は本当にクールなソリューションを見つけましたUpdating Your Form from Another Thread without Making Delegates for Every Type of Update

答えてくれてありがとう!!!

4

4 に答える 4

1

バックグラウンドワーカーのcompleted-eventでCrossThreadExceptionを回避するには、コールバックメソッドを次のようにラップします。

public void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (this.InvokeRequired)
    {
        this.Invoke(new RunWorkerCompletedEventHandler(WorkerCompleted), new {sender, e});
    }
    else 
    {
        // Business logic goes here
    }
}

通常、elseブロックのGridViewにロードされたデータを入力します。一方、長時間実行されるバックグラウンドタスクから段階的にGridViewにデータを入力する場合は、バックグラウンドワーカーからのコールバックを使用して、同様の手法でこれを実現できます。

public void Worker_DoWork(object sender, DoWorkEventArgs e)
{
   foreach (var someParameter in parameterList) // Long-running loop 
   {
     var data = LoadData(someParameter); // Load data for row X
     this.Invoke(new Action<object>(UpdateRow),new[]{data});  // Update on UI-thread
   }
}


public void UpdateRow(object data)
{
   // Code to populate DataGrid row X with data from argument
}

UIの更新を非同期で実行する場合は、Invokeの代わりにBeginInvokeを呼び出すことができることに注意してください。この場合、これは通常違いはありません。

于 2012-07-13T08:39:57.883 に答える
0

バックグラウンドワーカー/マルチスレッドを使用する場合は、フォームを更新するデリゲートを使用できます (UI スレッドで実行されます)。ここで例を参照してください: C# で別のスレッドから GUI を更新する方法は?

于 2012-07-13T08:46:49.827 に答える
0

BackgroundWorker と RunWorkerAsync を使用した簡単な例。お役に立てれば。

public partial class Form2 : Form
{

    BackgroundWorker worker = new BackgroundWorker();

    public Form2()
    {

        worker.WorkerReportsProgress = true;
        worker.WorkerSupportsCancellation = true;

        worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
        worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);

        InitializeComponent();
    }

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        int totalSteps = 5;
        for (int i = 1; i <= totalSteps; i++)
        {
            Thread.Sleep(1000);
            worker.ReportProgress(i);
        }
    }

    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;
    }

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        resultText.Text = "Worker complete";
        btnDoWork.Enabled = true;
        progressBar1.Visible = false;
    }

    private void btnDoWork_Click(object sender, EventArgs e)
    {
        progressBar1.Visible = true;
        worker.RunWorkerAsync();
    }

}
于 2012-07-13T10:24:40.550 に答える
0

Control.Invokeバックグラウンド ワーカー プロセスは正しい方法です。フォーム要素を変更するすべての呼び出しでメソッド ラッパーが使用されるようにすることで、「クロス スレッド操作」の例外をすべて排除する必要があります。

于 2012-07-13T08:38:01.763 に答える