我在一个按钮的单击事件里启动了一个线程,做一个耗时的操作,同时在这个操作了动态改变主窗体里一个控件的状态和text值。可是线程开启后主窗体不能动,其他控件的状态也是在这个线程结束后才改变的,并不是随着程序运行动态改变的。请问这是怎么回事?难道子线程操作主线程的控件要等线程结束后才可以,还有在子线程运行时主窗体为什么是假死状态,不能操作? private void PlayButton_Click(object sender, EventArgs e)
        {           
            TransmitThread = new Thread(new ThreadStart(TransmitThreadMethod));
            TransmitThread.IsBackground = true;
            TransmitThread.Start();           
        }
        private void TransmitThreadMethod()
        {
            MethodInvoker mi = new MethodInvoker(StupTransmit);           
           ));
            this.BeginInvoke(mi);
        }
        /// <summary>
        /// 数据传输方法
        /// </summary>
        private void StupTransmit()
        {
            PlayButton.Enabled = false;          
            ....            这里边循环对主窗体控件属性改变的代码。
            ......        }

解决方案 »

  1.   

    1.1运行在线程中直接同步访问控件 但是不推荐这么做
    所以在2.0中该为必须使用委托方式来访问控件你可以需要使用异步的方法来操作 就不会有主线程假死状态了例如:
    th1 = new Thread(new ThreadStart(FunInvo));
    th1.IsBackground = true;
    …………
    private void FunInvo()
    {
    MethodInvoker mi = new MethodInvoker(FunInvoFunt);


    //在窗体上调用 BeginInvoke
    this.BeginInvoke(mi);
    Thread.Sleep(300) ;

    }private void FunInvoFunt()
    {
       //ToDo yourwork Here
    }
      

  2.   

    To   jiatong1981(末日之痕)   我已经使用委托方式来访问控件了!!!
      

  3.   

    你可以需要使用异步的方法来操作 就不会有主线程假死状态了例如:
    th1 = new Thread(new ThreadStart(FunInvo));
    th1.IsBackground = true;
    …………
    private void FunInvo()
    {
    MethodInvoker mi = new MethodInvoker(FunInvoFunt);


    //在窗体上调用 BeginInvoke
    this.BeginInvoke(mi);
    Thread.Sleep(300) ;

    }private void FunInvoFunt()
    {
       //ToDo yourwork Here
    }
      

  4.   

    里面改变控件属性我都用了委托哦!private void WriteTransmitInfo(string info)
            {
                if (TransmitInfo.InvokeRequired)
                {              
                    MyInfoInvoke m = new MyInfoInvoke(WriteTransmitInfo);
                    this.Invoke(m, new object[] { info });
                }
                else
                {               
                    TransmitInfo.Text = info;               
                }
            }可是主界面还是假死状态!!!
      

  5.   

    private void WriteTransmitInfo(string info)
            {
                if (TransmitInfo.InvokeRequired)
                {              
                    MyInfoInvoke m = new MyInfoInvoke(WriteTransmitInfo);//??递归调用?
                    this.Invoke(m, new object[] { info });
                }
                else
                {               
                    TransmitInfo.Text = info;               
                }
            }
      

  6.   

    To  jiatong1981(末日之痕)看清楚了在回答!@!!什么递归调用,上面有if (TransmitInfo.InvokeRequired)我的程序一切运行正常!就是在线程没完的时候主界面不能动!!!!
      

  7.   

    private delegate void DlgateText(string text);private void UpdateText(string text)
    {
        if(this.InvokeRequired)
        {
            this.Invoke(new DlgateText(UpdateText), new object[]{text});
            Thread.Sleep(500) ;
        }
        else
        {
            yourTextBox.Text = text;
        }
    }
    ……我刚才可能看走眼了 因该这么写 估计lz也是这样写的吧?
      

  8.   

    如果StupTransmit()方法只是简单的操作一下界面控件,改变属性什么的,应该不会出现主界面假死的问题。可能是StupTransmit()方法中有大量其它的操作引起的。从上LZ的代码看,启动的这个线程并没有起到什么作用,因为所有的操作还是交给主线程完成的。应该把除控件操作部分的代码放在启动的线程中去完成, 在线程运行过程中,涉及界面操作的调用再用委托的方式,这样才能避免主界面假死的情况。
      

  9.   

    汗 被点名批评了 下次一定看仔细再说话……BTW:ls分析的很细致
      

  10.   

    private void PlayButton_Click(object sender, EventArgs e)
            {           
                TransmitThread = new Thread(new ThreadStart(TransmitThreadMethod));
                TransmitThread.IsBackground = true;
                TransmitThread.Start();           
            }
            private void TransmitThreadMethod()
            {
                MethodInvoker mi = new MethodInvoker(StupTransmit);           
               ));
                this.BeginInvoke(mi);
            }
            /// <summary>
            /// 数据传输方法
            /// </summary>
            private void StupTransmit()
            {
                PlayButton.Enabled = false;          
                ....            这里边循环对主窗体控件属性改变的代码。
                ......        }        从你的代码看不出多线程的用途与必要,其结果肯定是主窗体处于假死状态
            
            假设线程只执行一次用委托即可                private void TransmitThreadMethod()
            {
                MethodInvoker mi = new MethodInvoker(StupTransmit);           
               ));
                this.BeginInvoke(mi);
            }
      TransmitThreadMethod()这个方法只执行一次就报废了,结果是异步委托切换到UI线程
    UI线程工作
            private void StupTransmit()
            {
                PlayButton.Enabled = false;          
                ....            这里边循环对主窗体控件属性改变的代码。
                ......        }
    这里面的循环都是在UI线程进行,就如同一个单线程,程序不假死么?
      

  11.   

    用  Application.DoEvents(); 还勉强可以用
    不过感觉这不是解决的根本之道!还得请高手解决一下
      

  12.   

    在非界面线程中使用sleep方式是解决之道
      

  13.   

    直接调用 StupTransmit()private void TransmitThreadMethod()
    {
                StupTransmit();
    }