异步更新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,

View Code
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,总之,条条大道通罗马,重要的不是招式,是内功,是思想,思想理解了,招式自然也就信手拈来了。

由于时间比较匆忙,整理的比较乱,这里算是一个提纲吧,以后有时间在细写。

posted on 2013-01-06 16:42  MikeRen  阅读(2470)  评论(0编辑  收藏  举报

导航