WPF 之 线程使用
但凡涉及到图形界面,往往的设计都是不支持或者不推荐使用多个线程操作界面内容。而且通常会有一个专门的线程调度器来处理任务线程和界面线程的问题。
下面提供两个方案:
1、使用Dispatcher.BeginInvoke
这个方法简单暴力适合小工作量的修改一些界面内容。使用Dispatcher.BeginInvoke()会将代码安排为调度程序的一个任务。
步骤
- 使用Thread新建并开始一个线程
- 在新建的线程处理函数中需要修改界面的时候获取界面的dispatcher
- 使用Dispatcher的BeginInvoke方法指定一个线程优先级,和一个委托,这个委托时用于修改界面内容的
下面给出一部分代码
//新建线程 Thread thread = new Thread(UpdateTextRight); thread.Start();
下面是新线程中的方法
//这个事例刚好是先窗体类中定义的,所以获取Dispatcher变得比较方便,而且使用了匿名委托.在通常的代码中会把委托给分离出去比较好. private void UpdateTextRight() { this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart) delegate() { txt.Text = "Here is some new text."; } ); }
2、使用BackgroupWorker
这个类是专门用于简化Windows Form程序与线程相关的问题设计的,同样适用于WPF程序.适合于一个长期的后台进程,支持进度通知,取消支持,完成通知等功能。
使用方法也很简单,创建一个BackfruopWorker实例,它有几个事件.
DoWork事件会在另外一个线程中执行,用RunWorkerAsync()启动.所以在这个事件中不要去处理修改界面的事情
RunWorkerCompleted事件,在DoWork事件返回时(正常或者异常返回),在图形的线程中执行,所以可以修改界面
ProgressChanged事件,使用ReportProgress()方法调用,同时是在图形界面的线程中执行,通常负责修改一下进度条什么的.而ReportProgress()方法,通常会在DoWork的事件 中调用,然后给一个百分比的值.要使用这个功能,需要把WorkerReportsProgress属性设置成true
另外值得一说的是,要取消支持需要把WorkerSupportsCancellation属性设为true,使用CancelAsync()方法调用,但是这个调用不会终止进程,所以在DoWork事件中需要判断CancellationPending.
下面给出部分代码
创建BackgroundWorker实例
BackgroundWorker backgroundWorker; backgroundWorker = new BackgroundWorker(); backgroundWorker.DoWork += backgroundWorker_DoWork; backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted; //可以返回工作进度 backgroundWorker.WorkerReportsProgress = true; backgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged; //允许取消 backgroundWorker.WorkerSupportsCancellation = true;
开始执行DoWork
backgroundWorker.RunWorkerAsync();
DoWork事件范例,这个方法的内容是在另外一个线程,异步执行得
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { while(!backgroundWorker.CancellationPending) { //Do SomeThing //在合适的时候使用 //backgroundWorker.ReportProgress(i); //报告一下进度,其中i是0-100的整数 } //这里可以使用e.Result给一个返回值,如果有需要的话 }
进度改变时的处理事件,也就是修改一下进度条什么的
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) { progressBar.Value = e.ProgressPercentage; }
完成事件我就不演示,下面是取消任务的方法
private void cmdCancel_Click(object sender, RoutedEventArgs e) { backgroundWorker.CancelAsync(); }