4

SQLサーバーから照会されたグリッドにいくつかの情報を表示しようとしています。データ収集には約10秒かかることがあるので、UIスレッドをロックしたくありません。

私は現在次のようなコードを持っています:

ThreadPool.QueueUserWorkItem(DataUpdateThread, new UpdateParams(year));  

private struct UpdateParams
{
    internal string year;

    internal UpdateParams(string year)
    {
        this.year = year;
    }
}

private void DataUpdateThread(object state)
{
    DataTable dTable = new DataTable();
    try
    {
        this.Invoke((MethodInvoker)delegate
        {
            //stop data editing on the grid
            //scrolling marquee for user
            marquee.Visible = true;
            marquee.Enabled = true;
            grdMain.Visible = false;
            grdMain.DataSource = null;
        });

            UpdateParams parameters = (UpdateParams)state;            
            dTable = GetData(parameters.year);
    }
    catch (Exception ex)
    {
        this.Invoke((MethodInvoker)delegate
        {
            //log error + end user message
        });
    }
    finally
    {
        this.Invoke((MethodInvoker)delegate
        {
            grdMain.DataSource = dTable;
            grdMainLevel1.RefreshData();
            marquee.Visible = false;
            marquee.Enabled = false;
            grdMain.Visible = true;
        });
   }
}

これは、更新が完了する前にフォームが閉じられている場合を除いて、ほとんどの場合機能し、次のエラーでクラッシュします。

ウィンドウハンドルが作成されるまで、コントロールでInvokeまたはBeginInvokeを呼び出すことはできません。

フォームが存在しなくなったためにエラーが発生することを理解しています。そのため、finallyセクションがUIスレッドでメソッドを呼び出そうとすると、呼び出せなくなります。

このすべてを行うためのより良い方法はありますか?私は呼び出しエラーを処理できると思いますが、それは厄介に見え、おそらくもっと簡単な方法を逃したと思います。

4

3 に答える 3

4

フォームが閉じられているかどうかを確認でき、フォームが閉じられている場合は呼び出しを行わないでください。if (this.IsHandleCreated)動作するはずです。ただし、チェックとへの呼び出しの間にフォームを閉じることができるため、これでも問題が発生する可能性がありますBeginInvoke。唯一の「完全な証拠」の解決策は、呼び出し全体をtry/catchで囲むことです。

于 2010-10-25T10:40:24.853 に答える
1

InvokeRequired()前に使用してみてくださいInvoke()

于 2010-10-25T10:55:23.387 に答える
1

Invokeアプリのどこからでもアクセスできる特別な WinFormsSynchronizationContextを舞台裏で使用します。SynchronizationContext.Current

Reflectorを突っついた後の訂正: 実際には、Invoke は PostMessage を介してマーシャリングする直接的な方法に進みます。バックグラウンドで SynchronizationContext を利用するのは BackgroundWorker です。ウィンドウ ハンドルがない場合は、Invoke がスローされます。

基本的に、スレッドを開始する前に変数に格納する必要があります。たとえば、まだ UI スレッドにいるときに、スレッドのコードでコンテキストのPostまたはメソッドを使用する必要があります。Sendそうすることで、ウィンドウハンドルなしで適切にマーシャリングされます。

于 2010-10-25T11:14:25.657 に答える