您的位置:首页 > 其它

异步委托跨线程访问控件解决界面卡死

2015-08-06 15:57 453 查看
下面来看第二种方案,就是使用delegate和invoke来从其他线程中控制控件信息。网上有很多人写了这种控制方式,然而我看了很多这种帖子,表明上看来是没有什么问题的,但是实际上并没有解决这个问题,首先来看网络上的那种不完善的方式:
public partial class Form1 : Form

    {

        private delegate void FlushClient();//代理

        public Form1()

        {

            InitializeComponent();

        }

        private void Form1_Load(object sender, EventArgs e)

        {

            Thread thread = new Thread(CrossThreadFlush);

            thread.IsBackground=true;

            thread.Start();

        }

        private void CrossThreadFlush()

        {

            //将代理绑定到方法

            FlushClient fc = new FlushClient(ThreadFuntion);

            this.BeginInvoke(fc);//调用代理

        }

        private void ThreadFuntion()

        {

            while (true)

            {

                this.textBox1.Text = DateTime.Now.ToString();

                Thread.Sleep(1000);

            }

        }

    }

       使用这种方式我们可以看到跨线程访问的异常没有了。但是新问题出现了,界面没有响应了。为什么会出现这个问题,我们只是让新开的线程无限循环刷新,理论上应该不会对主线程产生影响的。其实不然,这种方式其实相当于把这个新开的线程“注入”到了主控制线程中,它取得了主线程的控制。只要这个线程不返回,那么主线程将永远都无法响应。就算新开的线程中不使用无限循环,使可以返回了。这种方式的使用多线程也失去了它本来的意义。

 现在来让我们看看推荐的解决方案(建议用该方案):

public partial class Form1 : Form

    {

        private delegate void FlushClient();//代理

        public Form1()

        {

            InitializeComponent();

        }

        private void Form1_Load(object sender, EventArgs e)

        {

            Thread thread = new Thread(CrossThreadFlush);

            thread.IsBackground = true;

            thread.Start();

        }


        private void CrossThreadFlush()

        {

            while (true)

            {

                //将sleep和无限循环放在等待异步的外面

                Thread.Sleep(1000);

                ThreadFunction();

            }

        }

        private void ThreadFunction()

        {

            if (this.textBox1.InvokeRequired)//等待异步

            {

                FlushClient fc = new FlushClient(ThreadFunction);

                this.Invoke(fc);//通过代理调用刷新方法

            }

            else

            {

                this.textBox1.Text = DateTime.Now.ToString();

            }

        }

    }


       运行上述代码,我们可以看到问题已经被解决了,通过等待异步,我们就不会总是持有主线程的控制,这样就可以在不发生跨线程调用异常的情况下完成多线程对winform多线程控件的控制了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: