在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
为了让程序尽快响应用户操作,在开发Windows应用程序时经常会使用到线程。对于耗时的操作如果不使用线程将会是UI界面长时间处于停滞状态,这种情况是用户非常不愿意看到的,在这种情况下我们希望使用线程来解决这个问题。 下面是一个使用多线程操作界面UI的代码: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Threading; namespace ThreadPoolDemo { public partial class ThreadForm : Form { public ThreadForm() { InitializeComponent(); } private void btnThread_Click(object sender, EventArgs e) { Thread thread = new Thread(new ThreadStart(Run)); thread.Start(); } private void Run() { while (progressBar.Value < progressBar.Maximum) { progressBar.PerformStep(); } } } } 程序的界面如下: CheckForIllegalCrossThreadCalls属性 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading; namespace ThreadPoolDemo { public partial class ThreadForm : Form { public ThreadForm() { InitializeComponent(); } private void btnThread_Click(object sender, EventArgs e) { //指示是否对错误线程的调用,即是否允许在创建UI的线程之外访问线程 CheckForIllegalCrossThreadCalls = false; Thread thread = new Thread(new ThreadStart(Run)); thread.Start(); } private void Run() { while (progressBar.Value < progressBar.Maximum) { progressBar.PerformStep(); } } } }
这样再执行程序就不会抛出异常了。 不过使用上面的代码我们可能还有些犯嘀咕,毕竟是不允许直接在线程中直接操作界面的,那么我们还可以用Invoke方法。 Invoke方法来操作界面 下面是一个例子: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading; namespace ThreadPoolDemo { public partial class ThreadForm : Form { //定义delegate以便Invoke时使用 private delegate void SetProgressBarValue(int value); public ThreadForm() { InitializeComponent(); } private void btnThread_Click(object sender, EventArgs e) { progressBar.Value = 0; //指示是否对错误线程的调用,即是否允许在创建UI的线程之外访问线程 //CheckForIllegalCrossThreadCalls = false; Thread thread = new Thread(new ThreadStart(Run)); thread.Start(); } //使用线程来直接设置进度条 private void Run() { while (progressBar.Value < progressBar.Maximum) { progressBar.PerformStep(); } } private void btnInvoke_Click(object sender, EventArgs e) { progressBar.Value = 0; Thread thread = new Thread(new ThreadStart(RunWithInvoke)); thread.Start(); } //使用Invoke方法来设置进度条 private void RunWithInvoke() { int value = progressBar.Value; while (value< progressBar.Maximum) { //如果是跨线程调用 if (InvokeRequired) { this.Invoke(new SetProgressBarValue(SetProgressValue), value++); } else { progressBar.Value = ++value; } } } //跟SetProgressBarValue委托相匹配的方法 private void SetProgressValue(int value) { progressBar.Value = value; } } }
这个方法的功能跟上面的操作是一样的,只不过不需要设置CheckForIllegalCrossThreadCalls属性,而且还不会抛出异常,当然除了上面的方法之外,还可以使用BackgroundWorker类来完成同样的功能。 BackgroundWorker类操作界面 因为使用BackgroundWorker类操作UI界面的例子周公博客上已经有过例子,所以这里的例子代码注释比较简单,读者可以看周公以前的示例,这次所使用的代码示例如下: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading; namespace ThreadPoolDemo { public partial class ThreadForm : Form { //定义delegate以便Invoke时使用 private delegate void SetProgressBarValue(int value); private BackgroundWorker worker; public ThreadForm() { InitializeComponent(); } private void btnThread_Click(object sender, EventArgs e) { progressBar.Value = 0; //指示是否对错误线程的调用,即是否允许在创建UI的线程之外访问线程 //CheckForIllegalCrossThreadCalls = false; Thread thread = new Thread(new ThreadStart(Run)); thread.Start(); } //使用线程来直接设置进度条 private void Run() { while (progressBar.Value < progressBar.Maximum) { progressBar.PerformStep(); } } private void btnInvoke_Click(object sender, EventArgs e) { progressBar.Value = 0; Thread thread = new Thread(new ThreadStart(RunWithInvoke)); thread.Start(); } //使用Invoke方法来设置进度条 private void RunWithInvoke() { int value = progressBar.Value; while (value< progressBar.Maximum) { //如果是跨线程调用 if (InvokeRequired) { this.Invoke(new SetProgressBarValue(SetProgressValue), value++); } else { progressBar.Value = ++value; } } } //跟SetProgressBarValue委托相匹配的方法 private void SetProgressValue(int value) { progressBar.Value = value; } private void btnBackgroundWorker_Click(object sender, EventArgs e) { progressBar.Value = 0; worker = new BackgroundWorker(); worker.DoWork += new DoWorkEventHandler(worker_DoWork); //当工作进度发生变化时执行的事件处理方法 worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged); //当事件处理完毕后执行的方法 worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted); worker.WorkerReportsProgress = true;//支持报告进度更新 worker.WorkerSupportsCancellation = false;//不支持异步取消 worker.RunWorkerAsync();//启动执行 btnBackgroundWorker.Enabled = false; } //当事件处理完毕后执行的方法 void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { btnBackgroundWorker.Enabled=true; } //当工作进度发生变化时执行的事件处理方法 void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) { //可以在这个方法中与界面进行通讯 progressBar.Value = e.ProgressPercentage; } //开始启动工作时执行的事件处理方法 void worker_DoWork(object sender, DoWorkEventArgs e) { int value = progressBar.Value; while (value < progressBar.Maximum) { worker.ReportProgress(++value);//汇报进度 } } } } 当然,除了BackgroundWorker可以完成上面的功能之外,利用System.Windows.Forms.Timer类也能完场上面的功能,代码如下: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading; namespace ThreadPoolDemo { public partial class ThreadForm : Form { //定义delegate以便Invoke时使用 private delegate void SetProgressBarValue(int value); private BackgroundWorker worker; public ThreadForm() { InitializeComponent(); } private void btnThread_Click(object sender, EventArgs e) { progressBar.Value = 0; //指示是否对错误线程的调用,即是否允许在创建UI的线程之外访问线程 //CheckForIllegalCrossThreadCalls = false; Thread thread = new Thread(new ThreadStart(Run)); thread.Start(); } //使用线程来直接设置进度条 private void Run() { while (progressBar.Value < progressBar.Maximum) { progressBar.PerformStep(); } } private void btnInvoke_Click(object sender, EventArgs e) { progressBar.Value = 0; Thread thread = new Thread(new ThreadStart(RunWithInvoke)); thread.Start(); } //使用Invoke方法来设置进度条 private void RunWithInvoke() { int value = progressBar.Value; while (value< progressBar.Maximum) { //如果是跨线程调用 if (InvokeRequired) { this.Invoke(new SetProgressBarValue(SetProgressValue), value++); } else { progressBar.Value = ++value; } } } //跟SetProgressBarValue委托相匹配的方法 private void SetProgressValue(int value) { progressBar.Value = value; } private void btnBackgroundWorker_Click(object sender, EventArgs e) { progressBar.Value = 0; worker = new BackgroundWorker(); worker.DoWork += new DoWorkEventHandler(worker_DoWork); //当工作进度发生变化时执行的事件处理方法 worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged); //当事件处理完毕后执行的方法 worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted); worker.WorkerReportsProgress = true;//支持报告进度更新 worker.WorkerSupportsCancellation = false;//不支持异步取消 worker.RunWorkerAsync();//启动执行 btnBackgroundWorker.Enabled = false; } //当事件处理完毕后执行的方法 void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { btnBackgroundWorker.Enabled=true; } //当工作进度发生变化时执行的事件处理方法 void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) { //可以在这个方法中与界面进行通讯 progressBar.Value = e.ProgressPercentage; } //开始启动工作时执行的事件处理方法 void worker_DoWork(object sender, DoWorkEventArgs e) { int value = progressBar.Value; while (value < progressBar.Maximum) { worker.ReportProgress(++value);//汇报进度 } } //使用System.Windows.Forms.Timer来操作界面能 private void btnTimer_Click(object sender, EventArgs e) { progressBar.Value = 0; //注意在.net中有多个命名空间下存在Timer类,为了便于区别,使用了带命名空间形式 System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer(); timer.Interval = 1; timer.Tick += new EventHandler(timer_Tick); timer.Enabled = true; } //Timer中要定期执行的方法 void timer_Tick(object sender, EventArgs e) { int value = progressBar.Value; if (value < progressBar.Maximum) { progressBar.Value = value+100; } } } } 总结:本篇主要讲述了使用线程操作Windows应用程序界面的方法,这些方法在编写多线程的UI程序时可以参考。 周公 2010-01-11 |
请发表评论