2

次のコード スニペットでAddRow()は、非 UI スレッドから呼び出されます。

  public partial class Form1 : Form
  {
    public delegate void InvokeDelegate();

    ...
    SqlConnection mSqlConnection = new SqlConnection("Data Source=" + Environment.MachineName + "\\SQLEXPRESS; Initial Catalog=orderDB; Integrated Security=TRUE; MultipleActiveResultSets=True;");

    DataSet mDataSet = new DataSet();
    SqlDataAdapter mSqlDataAdapter = new SqlDataAdapter();


    ...
    private void UpdateGridView()
    {
      if (mSqlConnection.State == ConnectionState.Closed)
        mSqlConnection.Open();

      mSqlDataAdapter.SelectCommand = new SqlCommand("SELECT * FROM customerTable", mSqlConnection);
      mDataSet.Clear();
      mSqlDataAdapter.Fill(mDataSet);
      dataGridView1.DataSource = mDataSet.Tables[0];

      if (mSqlConnection.State == ConnectionState.Open)
        mSqlConnection.Close();
    }


    public void AddRow(int field1, int field2, int field3)
    {
      mSqlDataAdapter.InsertCommand = new SqlCommand("INSERT INTO customerTable VALUES(@field1, @field2, @field3)", mSqlConnection);

      mSqlDataAdapter.InsertCommand.Parameters.Add("@field1", SqlDbType.Int).Value = field1;
      mSqlDataAdapter.InsertCommand.Parameters.Add("@field2", SqlDbType.Int).Value = field2;
      mSqlDataAdapter.InsertCommand.Parameters.Add("@field3", SqlDbType.Int).Value = field3;

      mSqlConnection.Open();
      mSqlDataAdapter.InsertCommand.ExecuteNonQuery();
      dataGridView1.BeginInvoke(new InvokeDelegate(UpdateGridView)); // UpdateGridView() won't work from a non-UI thread
      mSqlConnection.Close();

    }
}

AddRow()非 UI スレッドから呼び出さなければならない前に、私はUpdateGridView()直接呼び出されていましたが、問題なく動作していました。しかしAddRow()、UI スレッドからの呼び出しが保証されなくなったため、直接呼び出しをdataGridView1.BeginInvoke().

これを行うとすぐに、フォームベースのアプリケーションがいくつかの呼び出しSystem.InvalidOperationExceptionごとにスローを開始し、次のメッセージでステートメント ( ! ) を中断しました。AddRow()mSqlDataAdapter.Fill(mDataSet);

リーダーが閉じているときに Read を呼び出すのは無効です

私の質問はなぜですか?

  1. 何のリーダー?DataAdapterの?SqlConnection の? DataGridView のデータ ソース?
  2. BeginInvoke()mSqlConnection のOpen()Close()で囲み、mSqlConnection が開いていない場合は (もう一度!) 開いていますが、どうしてこの「閉じた」エラーが表示されるのでしょうか?
  3. この問題を解決する正しい方法は何ですか? (つまり、非 UI スレッドから DataGridView を更新する)
4

2 に答える 2

2

問題は確かに競合状態によるものです。

接続を閉じるのに適切な場所ではないため、UpdateGridView からこれらの 2 行を削除します。

 if (mSqlConnection.State == ConnectionState.Open)
    mSqlConnection.Close();

IAsyncResultを使用して待機ハンドルを取得し、スレッドが GridUpdate を完了するのを待ちます。

 IAsyncResult Result = dataGridView1.BeginInvoke(new InvokeDelegate(UpdateGridView));
 Result.AsyncWaitHandle.WaitOne();
 mSqlConnection.Close();
于 2012-10-26T22:08:35.903 に答える
0

レースの問題があると思います。スレッドのコードのこの部分を見てください。

 dataGridView1.BeginInvoke(new InvokeDelegate(UpdateGridView)); 
 mConnection.Close();

BeginInvokeは、そのようなことが制御に便利な場合にデリゲートを実行します。したがって、スレッドから呼び出すと、UIスレッドの入力が開始されます。これは長く続く可能性があり(テーブルからevrythingを取得しています)、データをフェッチしているときに、別のスレッドで接続を閉じるために呼び出して閉じます。たまにしか発生しないとおっしゃいましたが、ほとんどの場合、スレッドが接続を閉じてUpdateGridView()メソッドで再度開きますが、スレッドが接続を閉じる前にデータセットの入力を開始することもあります。接続の開閉を同期させる必要があります。

これら2つを切り替えると問題は解決しますが、毎回2つの接続を確立します。

mConnection.Close();
dataGridView1.BeginInvoke(new InvokeDelegate(UpdateGridView));
于 2012-10-26T21:45:22.537 に答える