如何在子线程中通过安全调用方法操作窗体控件

 在查询海量数据时,由于查询需要时间,因此要在查询的同时显示状态信息以通知用户当前正在进行的操作,通常采用多线程进行处理,但是初学者常常使用如下类似的代码:

         // button按钮的click事件处理函数
         private   void  buttonBookStat_Click( object  sender, EventArgs e)
        {
            ThreadStart tds1 
=   new  ThreadStart(prompt);
            Thread td1 
=   new  Thread(tds1);
            td1.Priority 
=  ThreadPriority.Normal;
            td1.Start();

            ThreadStart tds2 
=   new  ThreadStart(showBooksInfo);
            Thread td2 
=   new  Thread(tds2);
            td2.Priority 
=  ThreadPriority.Normal;
            td2.Start();
        }

        
// 显示提示
         private   void  prompt()
        {
            
this .labelPrompt.Text  =   " 正在查询,请稍侯...... " ;
        }

        
// 查询并绑定到窗体控件datagridview1
         private   void  showBooksInfo()
        {
            
string  sql  =   " select ......... " ;

            
try
            {
                SqlDataAdapter da 
=   new  SqlDataAdapter(sql, conn);
                DataSet ds 
=   new  DataSet();
                da.Fill(ds, 
" table1 " );

                
this .dataGridView1.AutoGenerateColumns  =   true ;
                
this .dataGridView1.DataSource  =  ds;
                
this .dataGridView1.DataMember  =   " table1 " ;

                
this .labelPrompt.Text  =   " 查询完毕 " ;
            }
            
catch  (SqlException er)
            {
                MessageBox.Show(er.Message);
            }
        }

这样的代码在子线程中操作窗体控件,盖茨大叔说是不安全的,但我用VS2005编译并不报错,也能正常运行,不过,运行时还是出了问题,在上述例子中datagridview控件的滚动条不能正常显示,无法使用滚动条滚动显示数据,看来,如果要在子线程中操作窗体控件,还是得采用线程安全调用的方式。要使用安全调用的方式,必须先定义一个委托,其签名与我们要操作控件的函数相同,步骤如下:

1.定义一个与窗体控件操作方法签名相同的委托

2.定义操作窗体控件的方法

3.定义一个安全调用方法,用2中的方法实例化我们定义的委托

4.在线程中调用3中的安全方法

因此,我们将上述代码作一修改,红色为新增和改动代码

//定义委托
        delegate void mydelegate();

        
//button按钮的click事件处理函数
        private void buttonBookStat_Click(object sender, EventArgs e)
        {
            ThreadStart tds1 
= new ThreadStart(promptSafe);
            Thread td1 
= new Thread(tds1);
            td1.Priority 
= ThreadPriority.Normal;
            td1.Start();

            ThreadStart tds2 
= new ThreadStart(showBooksInfoSafe);
            Thread td2 
= new Thread(tds2);
            td2.Priority 
= ThreadPriority.Normal;
            td2.Start();
        }

        
//显示提示
        private void prompt()
        {
            
this.labelPrompt.Text = "正在查询,请稍侯......";
        }

        
//安全调用显示提示方法
        private void promptSafe()
        {
            
if (this.labelPrompt.InvokeRequired)
            {
                
                mydelegate showprompt = new mydelegate(prompt);
                
                this.Invoke(showprompt);
            }
            else

            {
                prompt();
            }
        }

        
//查询并绑定到窗体控件datagridview1
        private void showBooksInfo()
        {
            
string sql = "select .........";

            
try
            {
                SqlDataAdapter da 
= new SqlDataAdapter(sql, conn);
                DataSet ds 
= new DataSet();
                da.Fill(ds, 
"table1");

                
this.dataGridView1.AutoGenerateColumns = true;
                
this.dataGridView1.DataSource = ds;
                
this.dataGridView1.DataMember = "table1";

                
this.labelPrompt.Text = "查询完毕";
            }
            
catch (SqlException er)
            {
                MessageBox.Show(er.Message);
            }
        }

        
//安全调用查询
        private void showBooksInfoSafe()
        {
            
if (this.dataGridView1.InvokeRequired)
            {
                
//定义委托对象
                mydelegate showbooks = new mydelegate(showBooksInfo);
                
//因此线程占用大量CPU时间,因此让它分些CPU时间出来给其他线程
                Thread.Sleep(10);
                
//通过窗体的Invoke方法调用委托
                this.Invoke(showbooks);
            }
            
else

            {
                showBooksInfo();
            }
        }

再次编译运行,现在你会发现datagridview控件的滚动条又正常了,这就是安全调用的好处,它会解决一些莫名其妙出现的问题。

不过,我们解决了问题之后仍然存在疑问:到底这种不安全调用的方式问题出在哪?其底层的错误在什么地方?在上述具体问题中,不安全调用方式仍然可以给datagridview指定数据源并显示,但在滚动条那里出现问题,我们无法获知datagridview这个控件的底层实现方式,微软也只是笼统地说在线程中操作窗体控件需要安全方式

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值