线程与WinForm设计,防冻结,卡住窗体

简介:

2013-07-10

卡住很有可能是因为在窗体的Invoke里进行了大量运算。

一般情况,在线程中就仅仅进行和窗体无关的计算,必要时,使用Invoke进行一些窗体状态的更新,这样完全不会导致卡住冻结。

2010-09-25 18:57更新:根据各位朋友的回复,做了一些更新。

加入了BackgroundWorker和MethodInvoker

 

有时候我们在窗体的执行方法中,会延迟很久,那样就会造成操作窗体(界面)卡住(冻结)的情况出现,这样的用户体验非常糟糕。

在使用线程操作,则可能会避免这种情况。

因此我做了一个测试。

在这方面的设计,我也是初学者,因此,有不对的地方,请前辈指点迷津。

 

 

 

复制代码
///   <summary>
///  执行的主逻辑
///   </summary>
///   <param name="obj"></param>
private   void  RunMethod( object  obj)
{
    ThreadTest tt 
=   new  ThreadTest();
    
int  curValue  =   0 ;
    
for  ( int  i  =   0 ; i  <   20 ; i ++ )
    {
        curValue 
=  tt.GetRandomNum();
        
// 不添加5的项,主要为了添加业务复杂性
         while  (curValue  ==   5 )
        {
            Thread.Sleep(
2000 ); // 制造延迟,测试是否会冻结(卡)主窗口
            curValue  =  tt.GetRandomNum();
        }
        Thread.Sleep(
2000 ); // 制造延迟,测试是否会冻结(卡)主窗口
        
        
if  ( this .InvokeRequired)
        {                   
            
this .Invoke( new  MethodInvoker( delegate ()
            {
                
this .lsbShow.Items.Add(curValue);
                
this .lsbShow.SelectedIndex  =  lsbShow.Items.Count  -   1 ;
            }));
        }
        
else
        {
            lsbShow.Items.Add(curValue);
        }
    }
    
this .Invoke( new  MethodInvoker( delegate ()
    {
        
this .btnRun.Enabled  =   true ;
        
this .btnThread.Enabled  =   true ;
        btnBackgroundWorker.Enabled 
=   true ;
        
this .lsbShow.Items.Add( " Done " );
        
this .lsbShow.SelectedIndex  =  lsbShow.Items.Count  -   1 ;
    }));
}
复制代码

 

 

用到的测试类

 

复制代码
public   delegate   void  CommonDelegate();
public   class  ThreadTest
{
    
public  ThreadTest() {  }
    
public   int  GetRandomNum()
    {
        Random rd 
=   new  Random();
        
return  rd.Next( 1 10 );
    }
}
复制代码

 

调用按钮事件

 

 

复制代码
private   void  btnRun_Click( object  sender, EventArgs e)
{
    RunStart();
    ThreadPool.QueueUserWorkItem(
new  WaitCallback(RunMethod));            
}

private   void  btnThread_Click( object  sender, EventArgs e)
{
    RunStart();
    Thread td 
=   new  Thread( new  ParameterizedThreadStart(RunMethod));
    td.Start(
"" );            
}
private   void  RunStart()
{
    lsbShow.Items.Clear();
    btnRun.Enabled 
=   false ;
    btnThread.Enabled 
=   false ;
    btnBackgroundWorker.Enabled 
=   false ;
}

private   void  btnBackgroundWorker_Click( object  sender, EventArgs e)
{
    RunStart();
    
using  (BackgroundWorker bw  =   new  BackgroundWorker())
    {
        bw.DoWork 
+=   new  DoWorkEventHandler(bw_DoWork);
        bw.RunWorkerAsync();
    }
}
void  bw_DoWork( object  sender, DoWorkEventArgs e)
{
    RunMethod(
"" );
}
复制代码

 

 

测试源码http://files.cnblogs.com/yelaiju/WinFormSynTest.rar



本文转自火地晋博客园博客,原文链接:http://www.cnblogs.com/yelaiju/archive/2010/09/25/1834266.html,如需转载请自行联系原作者

目录
相关文章
线程中使用SaveFileDialog不能弹出窗体
在子线程中使用 SaveFileDialog 无法弹出窗体,主要是我们需要用主线程去处理SaveFileDialog , 我们可以将子线程进行如下设置: public partial class Form1 : Form    {        public Form1()        {    ...
1083 0
【基础】多线程更新窗体UI的若干方法
如果您觉得文章对您有帮助,可以【打赏】博主或点击文章右下角【推荐】一下。您的鼓励是博主坚持原创和持续写作的最大动力!
564 0
|
C#
C#线程访问winform窗体控件
参考地址:http://www.cnblogs.com/jason-liu-blogs/archive/2012/09/08/2677008.html 添加: public Form() { InitializeComponent(); Control.
756 0
在C#中子线程如何操作主线程中窗体上控件
                                                       在C#中子线程如何操作主线程中窗体上控件         在C#中,直接在子线程中对窗体上的控件操作是会出现异常,这是由于子线程和运行窗体的线程是不同的空间,因此想要在子线程来操作窗体上的控件,是不可能简单的通过控件对象名来操作,但不是说不能进行操作,微软提供了Invoke的方法,其作用就是让子线程告诉窗体线程来完成相应的控件操作。
1428 0
|
C#
C#多线程编程实例 线程与窗体交互
C#多线程编程实例 线程与窗体交互 代码: public partial class Form1 : Form { //声明线程数组 Thread[] workThreads = new Thread[10]; publ...
678 0