日期:2014-05-17  浏览次数:20894 次

winform异步线程更新UI问题(求讨论,求指教,求保养)
刚才看到有人问为了winfrom中,在大数据绑定的时候出现画面假死的状态,为了解决这个问题希望通过再开一个线程来给控件绑定数据,可是画面还是会假死。
现在看到的方法有
1.掩耳盗铃法(Control.CheckForIllegalCrossThreadCalls = false;)
C# code

using System;
using System.Threading;
using System.Windows.Forms;

namespace ThreadTest
{
    public partial class Form1 : Form
    {        

        public Form1()
        {
            InitializeComponent();
            Control.CheckForIllegalCrossThreadCalls = false;//这一行是关键      
        }
       

        private void btnSet_Click(object sender, EventArgs e)
        {           
            Thread t = new Thread(new ParameterizedThreadStart(SetTextBoxValue));
            t.Start("Hello World");
        }


        void SetTextBoxValue(object obj) 
        {
            this.textBox1.Text = obj.ToString();
        }        
    }
}


这种方法是最方便,实现最简单的方式,但是这样等于是线程之间是去了限制,子线程能够直接控制父线程的控件,会出现线程之间的冲突,不是好的实现方式
2.利用BackgroundWorker
C# code

using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace ThreadTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();            
        }       

        private void btnSet_Click(object sender, EventArgs e)
        {
            //MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
            using (BackgroundWorker bw = new BackgroundWorker())
            {
                bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
                bw.DoWork += new DoWorkEventHandler(bw_DoWork);
                bw.RunWorkerAsync("Hello World");
            }
        }

        void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            //MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
            e.Result = e.Argument;//这里只是简单的把参数当做结果返回,当然您也可以在这里做复杂的处理后,再返回自己想要的结果(这里的操作是在另一个线程上完成的)
        }

        void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //这时后台线程已经完成,并返回了主线程,所以可以直接使用UI控件了
            this.textBox1.Text = e.Result.ToString();
            //MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
        }       
    }    
}


这种方式只能在异步结束后给控件赋值,
--即bw_DoWork是异步处理,异步处理过程中不能给控件赋值
--bw_RunWorkerCompleted方法中可以给控件赋值,可是这个过程不是异步的,如果在bw_RunWorkerCompleted中加上一个System.Threading.Thread.Sleep(3000);画面还是会假死
3.不使用BackgroundWorker,自己来写线程来实现类似于BackgroundWorker的处理

子线程给主线程成员赋值的迷惑
C# code

        // 代码中自己定义的按钮(非显示按钮)
        private Button testBtn = new Button();

        private void button1_Click(object sender, EventArgs e)
        {
            Thread thr = new Thread(ControlParent);
            thr.Start();
        }

        private void ControlParent()
        {
            Thread.Sleep(3000);
            // 给自己定义的按钮赋值没有问题
            testBtn.Text = "eeee";
            // 给画面上显示的按钮赋值,InvalidOperationException错误(这里迷糊了,子线程不能直接给主线程赋值,那么主线程是什么?)
            this.button1.Text = "asda";// InvalidOperationException!!!!!!!!!!!
        }



这里的两个按钮,同样是属于一个类,只不过一个显示在画面上,另一个只定义了没有显示,为什么一个赋值成功,另一个就是败了,求大哥大姐们来个破解之法,感激不尽。
PS:窗体的this.BeginInvoke只能不阻塞后面代码的执行,不能解决画面假死

以上描述够清楚了吧,希望坛子里的大牛们能够诲人不倦,相信不只是我迷糊,还会有不少人也在迷糊着,希望能够来人指教了,欢迎指教讨论,感激不尽

------解决方案--------------------
this.progressBar1.Invoke(new System.Action(delegate()
{