none
为什么用线程就不能给全局变量DS(DataSet)加入表呢?? RRS feed

  • 问题

  •         
            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));
            }
    2009年7月18日 9:08

答案

  • 您好,
    当在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
    2009年7月18日 11:23

全部回复

  • 您好,
    当在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
    2009年7月18日 11:23
  • 有没有好的办法, 我在后台加载数据到DataSEt的表中,但界面的其它控件不卡,也可以操作,窗体也可以移动,如在另一个TextBox中录数据等..
    谢谢!!
    2009年7月18日 16:01
  • 最简单的做法:不用我在上面的建议做法而是在您原来的代码上把addlistviewData(listView1);移动到loaddata方法的最后一行。
    2009年7月18日 16:44
  • 最简单的做法:不用我在上面的建议做法而是在您原来的代码上把addlistviewData(listView1);移动到loaddata方法的最后一行。
    我说的是加载Ds而不是显示在ListView上
    2009年7月19日 5:08
  • 最简单的做法:不用我在上面的建议做法而是在您原来的代码上把addlistviewData(listView1);移动到loaddata方法的最后一行。
    我说的是加载Ds而不是显示在ListView上

    如果单说加载,您自己发布的代码就可以,现在的问题不就是因为要显示的时候数据还没加载造成的吗?
    把加载和显示放在同一个线程上才能保证执行的先后顺序。
    2009年7月19日 13:37