积极答复者
为什么用线程就不能给全局变量DS(DataSet)加入表呢??

问题
-
void loaddata() { SqlConnection cn = new SqlConnection(cnstr); if (cn.State == ConnectionState.Closed) cn.Open(); string sel = "select invcode,invname,invspec,invunit from inventory"; SqlCommand cmd = new SqlCommand(sel, cn); SqlDataReader dr = cmd.ExecuteReader(); DataTable dt = new DataTable("zjh"); dt.Columns.Add("a", typeof(string)); dt.Columns.Add("b", typeof(string)); dt.PrimaryKey = new DataColumn[] { dt.Columns["a"] }; while (dr.Read()) { DataRow r = dt.NewRow(); r["a"] = dr[0].ToString(); r["b"] = dr[1].ToString(); dt.Rows.Add(r); Thread.Sleep(1); } cn.Dispose(); ds.Tables.Add(dt); } void addlistviewData(ListView lv) { DataTable dx = new DataTable(); dx = ds.Tables["zjh"]; //这里Ds没有表,用ds.Tables.Count.ToString(); 值为0 for (int i = 0; i < dx.Rows.Count; i++) { ListViewItem lvv = new ListViewItem(dx.Rows[i][0].ToString()); lvv.SubItems.Add(dx.Rows[i][1].ToString()); lv.Items.Insert(lv.Items.Count, lvv); } } DataSet ds = new DataSet(); Thread th = null; private void Form1_Load(object sender, EventArgs e) { listView1.View = View.Details; listView1.FullRowSelect = true; listView1.GridLines = true; listView1.Columns.Add("aa", 100, HorizontalAlignment.Left); listView1.Columns.Add("aa", 100, HorizontalAlignment.Left); listView1.Columns.Add("aa", 100, HorizontalAlignment.Left); listView1.Columns.Add("aa", 100, HorizontalAlignment.Left); } private void button1_Click(object sender, EventArgs e) { //为什么用线程就不能给变量DS(DataSet)加入表呢?? //直接调用loaddata()后,再用addlistviewData(listView1);却是可以的 th = new Thread(new ThreadStart(dosome)); timer1.Enabled = false; textBox2.Text = "this is ok"; addlistviewData(listView1); } private void dosome() { this.Invoke(new Action(loaddata)); }
答案
-
您好,
当在th = new Thread(new ThreadStart(dosome));这里启用多线程时。主窗口并不阻塞。代码继续运行。
所以到addlistviewData(listView1);这句时,loaddata还没来得及加载数据。所以Ds没有表。
这里面有时间先后的问题。在代码中并没有保证loaddata先执行,addlistviewData后执行。
如果在此基础上修改,可以用AutoResetEvent来重新设计,目的是在addlistviewData(listView1);执行前等待loaddata执行完毕。
个人建议修改方案:
1、声明一个AutoResetEvent m_AutoResetEvent = new AutoResetEvent(false);
2、在loaddata方法的最后一行增加 m_AutoResetEvent.Set();
3、在button1_Click里addlistviewData(listView1);调用前增加m_AutoResetEvent.WaitOne();例如:
private void button1_Click(object sender, EventArgs e)
{
th = new Thread(new ThreadStart(dosome));
timer1.Enabled = false;
textBox2.Text = "this is ok";
...... //在这里可以放更多其它的代码,这样设计成多线程才有意义
m_AutoResetEvent.WaitOne();
addlistviewData(listView1);
}
4、修改dosome 直接调用loaddata,不用通过Invoke来调用,只有在更新窗口控件的情况下才调用Invoke。因为您的代码loaddata并没有更新窗体控件,调用Invoke反而会使得线程重新邦回主线程。关于Invoke的机制,我在论坛中曾讨论过,请参考:http://social.microsoft.com/Forums/zh-CN/2212/thread/b55060e1-6ae7-4f54-91a8-459faf64ab2a- 已标记为答案 zjh111 2009年7月18日 15:52
全部回复
-
您好,
当在th = new Thread(new ThreadStart(dosome));这里启用多线程时。主窗口并不阻塞。代码继续运行。
所以到addlistviewData(listView1);这句时,loaddata还没来得及加载数据。所以Ds没有表。
这里面有时间先后的问题。在代码中并没有保证loaddata先执行,addlistviewData后执行。
如果在此基础上修改,可以用AutoResetEvent来重新设计,目的是在addlistviewData(listView1);执行前等待loaddata执行完毕。
个人建议修改方案:
1、声明一个AutoResetEvent m_AutoResetEvent = new AutoResetEvent(false);
2、在loaddata方法的最后一行增加 m_AutoResetEvent.Set();
3、在button1_Click里addlistviewData(listView1);调用前增加m_AutoResetEvent.WaitOne();例如:
private void button1_Click(object sender, EventArgs e)
{
th = new Thread(new ThreadStart(dosome));
timer1.Enabled = false;
textBox2.Text = "this is ok";
...... //在这里可以放更多其它的代码,这样设计成多线程才有意义
m_AutoResetEvent.WaitOne();
addlistviewData(listView1);
}
4、修改dosome 直接调用loaddata,不用通过Invoke来调用,只有在更新窗口控件的情况下才调用Invoke。因为您的代码loaddata并没有更新窗体控件,调用Invoke反而会使得线程重新邦回主线程。关于Invoke的机制,我在论坛中曾讨论过,请参考:http://social.microsoft.com/Forums/zh-CN/2212/thread/b55060e1-6ae7-4f54-91a8-459faf64ab2a- 已标记为答案 zjh111 2009年7月18日 15:52