1. 程式人生 > >非同步委託跨執行緒訪問控制元件解決介面卡死

非同步委託跨執行緒訪問控制元件解決介面卡死

下面來看第二種方案,就是使用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多執行緒控制元件的控制了。