程序在调试时报错:线程间操作无效: 从不是创建控件“tabControl1”的线程访问它。
如果直接运行就不会报这个错。程序是这样设计的:
1、有一个tabControl1控件,有tabPage1和tabPage2;
2、每个tabPage里分别放有dataGridView控件,用来查询从SQL数据库里查询的数据;
3、由于查询数据比较耗时,就在窗体下放添加了:toolStripProgressBar1,用来循环显示进底条;
4、button1用来进行数据查询,将数据查询与进度条显示作为线程运行;   proBarThread = new Thread(new ThreadStart(SetToolStripProgressBar));//SetToolStripProgressBar进度条方法
   proBarThread.Start();
   //开启进度条线程
   reportThread = new Thread(new ThreadStart(DataSetTabPage));//DataSetTabPage执行数据查询等一系列方法
   reportThread.IsBackground = true;//后台线程
   reportThread.Start();
   //开启数据查询线程                        
   timer1.Enabled = true;5、另用一个timer1控件,来判断前面两个线程是否结束,然后再执行一些内容;
网上有说用这个方法:Control.CheckForIllegalCrossThreadCalls = false;但据说是不安全的,也有说有委托的方法,结果对是单线程运行,不能让查询数据与进度条同步进行。请问大家有好的办法没有?

解决方案 »

  1.   

    是的,那样不好。你可以把对界面的操作都用这句包裹起来。this.Invoke((EventHandler)delegate
    {
    //界面代码1
    //界面代码2
    //...
    });
      

  2.   

    Control.Invoke
    Control.BeginInvoke
    请自行百度
      

  3.   


    ....
    你原本写的界面代码用我给你的包起来,原来代码在哪就写哪。晕啊。你DataSetTabPage不是个线程函数么?
    public void DataSetTabPage()
    {
        //非界面操作
        this.Invoke((EventHandler)delegate{this.Progress1.Value = 0;}
        //非界面操作
        while(...)
        {
            //其他
            this.Invoke((EventHandler)delegate
                        {
                            this.什么的更新。
                            this.Progress1.Value++;
                        }
        }
    }
      

  4.   

    Windows控件,只能在创建它的线程里访问它,
    在不同的线程访问,要通过当前线程的Invoke方法来调用。  
    http://topic.csdn.net/u/20100716/20/c4784bd0-fc2d-4f1e-adf8-2d4280beb5b6.html
      

  5.   

    我用wuyazhe前辈的方法,将SetToolStripProgressBar与DataSetTabPage方法都包起来试了,调试就报错了,进底条会正常显示,但数据却查不出来了。下面是修改SetToolStripProgressBar方法,不知道对不对?/// <summary>
            /// 设置进度条显示
            /// </summary>
            private void SetToolStripProgressBar()
            {
                this.Invoke((EventHandler)delegate
                {
                    toolStripProgressBar1.Visible = true;
                    toolStripStatusLabel3.Width = statusStrip1.Width - toolStripStatusLabel1.Width - toolStripStatusLabel2.Width - toolStripProgressBar1.Width - toolStripStatusLabel10.Width - toolStripStatusLabel11.Width - 22;
                      toolStripProgressBar1.Value = 0;
                    toolStripProgressBar1.Minimum = 0;
                    toolStripProgressBar1.Maximum = 100;
                    toolStripProgressBar1.Step = 1;
                    while (toolStripProgressBar1.Value < 100)
                    {
                        if (toolStripProgressBar1.Value == 99)
                        {
                            toolStripProgressBar1.Value = 0;
                        }
                        Thread.Sleep(50);
                          toolStripProgressBar1.Value++;
                    }
                }
                );
            }
      

  6.   

    invoke就是辅助线程和主线程同步的,你invoke开始,到invoke结束后,其他操作ui的才会执行。
      

  7.   

    有两个方法
    一个是把控件设置成 线程不安全的  这样爱人以线程都可以调用
    一个是在线程中 使用 控件 或者窗体的Invoke 方法 
    this.Invoke(new Action(delegate
    {
    //改变控件属性
    }));这样写最好奥  用Action
      

  8.   

    我的方法很复杂,没办法套用过来。
    private void button3_Click(object sender, EventArgs e)
    {
    try
         {
             this.Cursor = System.Windows.Forms.Cursors.WaitCursor;
             proBarThread = new Thread(new ThreadStart(SetToolStripProgressBar));
             proBarThread.Start();    //开启进度条线程
              reportThread = new Thread(new ThreadStart(DataSetTabPage));
             reportThread.IsBackground = true;//后台线程
              reportThread.Start();         //开启数据查询线程   
     
              //这里开两个线程的目的是让进度条显示与数据查询同步进行。           timer1.Enabled = true;
          }
          catch (Exception ex)
          {
               this.Cursor = System.Windows.Forms.Cursors.Default;
               MessageBox.Show(ex.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Error);
               return;
          }
    }
    其中:SetToolStripProgressBar方法是,界面中进度条循环不停地从0-100递增显示;
          DataSetTabPage方法是,从SQL数据库查询很多数据,并赋值给界面一些控件(如dataGridView1,label1,label2等);
          timer1.Enabled = true;方法是,判断DataSetTabPage是否执行完毕,然后再对界面中的一些显示进行设置(比如停止进度条递增,并隐藏掉;数据显示控件的格式等)由于自己水平有限,怎么弄也弄不好。
      

  9.   

    this.invoke()这个方法,我只能运行其中一个线程,要么进度条显示,要么进行数据查询,不能两个同步进行。
      

  10.   

    网上有这么一段代码说明,但就是不知道怎么同时运行进度条与数据查询两个方法的线程;using System.Threading;//添加线程的命名空间 namespace ppp{    public partial class Form1 : Form    {        public Form1()        {            InitializeComponent();        }         Thread t; //定义线程变量         private void button1_Click(object sender, EventArgs e)        {            t = new Thread(new ThreadStart(Threadp)); //实例化线程            t.Start();//启动线程        }         private delegate void setText();//定义一个线程委托   自定义方法Threadp,主要用于线程的调用。代码如下:        public void Threadp()        {            setText d = new setText(Threading); //实例化一个委托            this.Invoke(d); //在拥用此控件的基础窗体句柄的线程上执行指定的委托        }   自定义方法Threading,主要作于委托的调用。代码如下:        public void Threading()        {            textBox1.Text = "实现在子线程中操作主线程中的控件";            t.Abort();//关闭线程        }    }}
      

  11.   

    load中写 
     Control.CheckForIllegalCrossThreadCalls = false;//防止出现  线程间操作无效:
      

  12.   

    多线程操作 
    invoke  begininvoke
    可参考http://blog.csdn.net/yaohuang306/archive/2011/02/23/6201648.aspx
      

  13.   

    委托我试过,不知道为什么只能要么执行进度条显法,要么执行SQL查询,不能两者同步进行.
      

  14.   

    我有这个想法,为什么要用线程呢,很多时候没必要用线程,那么处理控件时也就没有必要用代理委托的方法了,那样不是很好吗?
    反正我不太习惯用delegate来做
      

  15.   

    谁能告诉这个委托该怎么处理呀?
    现有:SQL数据查询方法(方法中操作了界面的一些控件);
          进度条循环显示(方法中也操作了界面的控件);我是需要在点击界面查询按钮时,同步执行SQL数据查询与进度条循环显示,想必是应该开两个不同的线程运行,否则两个方法只能运行其中一个,怎么用委托的方法来实现?并且不知道如何实现当SQL数据查询方法执行完成之后,停止进度条的循环显示。