异步更新UI
在写多线程的时候突然发现自己新建的线程无法更新UI,一番猛查,了解到UI只能在创建他的线程中更新,其他线程是没有权限的,
只能通过这样的方式更新
this.Invoke或者this.BeginInvoke
WPF中Control类没有这方法,只能通过调配器
this.Dispatcher.BeginInvoke或者Invoke,前者是异步,后者是同步,也就是说前者不需要等待,就可以在调用线程中继续执行。
由于一般我们创建UI都是在主线程,所以我们常用的UI线程就是主线程,也就是说当主线程被占用的时候,UI是不会更新的,所以要想实时更新UI,在主线程中这样写
this.Dispatcher.BeginInvoke(new Action( () => { Thread.Sleep(1000); Debug.WriteLine(DateTime.Now.Millisecond.ToString()+"1"); this.textBox1.Text = "Completed!"; })); Debug.WriteLine(DateTime.Now.Millisecond.ToString() + "3"); this.Dispatcher.BeginInvoke(new Action( () => { Debug.WriteLine(DateTime.Now.Millisecond.ToString()+"2"); }));
是没有前途的,因为一直会占用主线程,而且执行的顺序是 3 1 2,可以看出,即使是异步,也会回到第一个更新UI的地方继续等待
想要连续更新UI,不能在主线程中等待,而是应该新建一个线程,在里面去执行比较耗时的操作,执行完毕后通过调用主线程的委托来更新UI,

protected void UpdateUI() { for (int i = 0; i < 100; i++) { Thread.Sleep(10); this.Dispatcher.BeginInvoke(new Action( () => { this.textBox1.Text += DateTime.Now.ToString(); this.textBox1.Text += "\r\n"; this.progressBar1.Value = i + 1; })); } } Thread thread = new Thread(UpdateUI); thread.Start();
这样
当然,如果纯粹为了更新UI,没有其他耗时的操作,比如图片不停的循环播放,Timer控件就可以达到目的,Interval属性设置间隔时间,Tick属性设置执行内容
执行比较耗时的操作,但需要不停的给UI反馈,BackgroundWorker是个不错的选择,关于创建新的线程,也有不同的方法,比如委托的BeginInvoke,直接new Thread或者new Task,也可以直接使用线程池ThreadPool.QueueUserWorkItem,总之,条条大道通罗马,重要的不是招式,是内功,是思想,思想理解了,招式自然也就信手拈来了。
由于时间比较匆忙,整理的比较乱,这里算是一个提纲吧,以后有时间在细写。