在以下代码段中,从非UI线程调用AddRow()
:
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();
}
}
在必须从非UI线程调用AddRow()
之前,我已直接调用UpdateGridView()
并且它完美无缺。但现在不再保证从UI线程调用AddRow()
,因此我用dataGridView1.BeginInvoke()
替换了直接调用。
我一做到这一点,我的基于表单的应用程序就开始每System.InvalidOperationException
次AddRow()
次调用mSqlDataAdapter.Fill(mDataSet);
,打破BeginInvoke()
声明(! )带有以下消息:
读取器关闭时调用Read的尝试无效
我的问题是为什么?
答案 0 :(得分:2)
问题当然是由于竞争条件。
从UpdateGridView中删除这两行,因为它不是关闭连接的正确位置。
if (mSqlConnection.State == ConnectionState.Open)
mSqlConnection.Close();
使用IAsyncResult检索等待句柄并等待线程完成GridUpdate。
IAsyncResult Result = dataGridView1.BeginInvoke(new InvokeDelegate(UpdateGridView));
Result.AsyncWaitHandle.WaitOne();
mSqlConnection.Close();
答案 1 :(得分:0)
我认为你遇到了种族问题,请在你的帖子中查看这部分代码:
dataGridView1.BeginInvoke(new InvokeDelegate(UpdateGridView));
mConnection.Close();
当这样的东西对于控件来说方便时,BeginInvoke将运行委托。所以你从线程中调用它并且它启动你的UI线程可以持续很长时间(你从表中得到的东西)并且在获取数据时,调用关闭连接在单独的线程中关闭它。你提到它只是偶尔发生,在大多数情况下,线程将关闭连接,你将在UpdateGridView()
方法中重新打开它,但有时,你会在线程关闭连接之前开始填充数据集。您应该同步打开和关闭连接。
切换这两个应解决您的问题,但每次都会建立两个连接:
mConnection.Close();
dataGridView1.BeginInvoke(new InvokeDelegate(UpdateGridView));