如何使用backgroundWorker进行异步操作
在应用程序中,可能会遇到一些执行耗时的功能操作,比如数据下载、复杂计算及数据库事务等,一般这样的功能会在单独的线程上实现,执行结束后结果显示到用户界面上,这样可避免造成用户界面长时间无响应情况。在.NET 2.0及以后的版本中,FCL提供了BackgroundWorker组件来方便的实现这些功能要求。
组件介绍
BackgroundWorker类位于System.ComponentModel 命名空间中,通过该类在单独的线程上执行操作实现基于事件的异步模式。下面对BackgroundWorker类的主要成员进行介绍。
BackgroundWorker类的第1个主要方法是RunWorkerAsync,该方法提交一个以异步方式启动运行操作的请求,发出请求后,将引发 DoWork 事件,在事件处理程序中开始执行异步操作代码。RunWorkerAsync 方法签名如下,
publicvoidRunWorkerAsync();
publicvoidRunWorkerAsync(Object argument);
如果异步操作需要操作参数,可以将其作为argument参数提供,由于参数类型为Object,因此访问时可能需要进行类型转换。
CancelAsync 方法提交终止异步操作的请求,并将 CancellationPending 属性设置为 true。需要注意的是,CancelAsync 方法是否调用成功,同WorkerSupportsCancellation 属性相关,如果允许取消执行的异步操作,需将WorkerSupportsCancellation 属性设置为true,否则调用该方法将抛出异常。CancelAsync方法不含参数,方法签名如下,
publicvoid CancelAsync();
调用 CancelAsync 方法时,BackgroundWorker的 CancellationPending 属性值将被设置为true,因此在编写单独线程中执行的辅助方法时,代码中应定期检查 CancellationPending 属性,查看是否已将该属性设置为 true,如果为true,应该结束辅助方法的执行。有一点需要注意的是,DoWork 事件处理程序中的代码有可能在发出取消请求时已经完成处理工作,因此,DoWork事件处理程序或辅助方法可能会错过设置CancellationPending属性为true的时机。在这种情况下,即使调用 CancelAsync方法发出了取消异步操作请求,RunWorkerCompleted 事件处理程序中RunWorkerCompletedEventArgs 参数的 Cancelled 标志也不会被设置为 true,这是在多线程编程中经常会出现的竞争条件问题,因此编写代码的时候需要考虑。
在执行异步操作时,如果需要跟踪异步操作执行进度,BackgroundWorker类提供了 ReportProgress 方法,调用该方法将引发 ProgressChanged 事件,通过注册该事件在事件处理程序中获取异步执行进度信息。方法签名如下:
publicvoidReportProgress(int percentProgress);
publicvoidReportProgress(int percentProgress,Object userState);
该方法包含两个版本,percentProgress表示进度百分比,取值为0-100,userState为可选参数表示自定义用户状态。
同CancelAsync 方法一样,BackgroundWorker的WorkerReportsProgress 属性设置为 true时,ReportProgress 方法才会调用成功,否则将引发InvalidOperationException异常。
上面已经提到了BackgroundWorker的3个属性,CancellationPending用来提示操作是否已经取消,WorkerReportsProgress和WorkerSupportsCancellation分别用来设置是否允许进度汇报和进行取消操作。
publicboolCancellationPending { get; }
publicboolWorkerReportsProgress { get; set; }
publicboolWorkerSupportsCancellation { get; set; }
另外一个会用到的属性是IsBusy,
publicbool IsBusy { get; }
通过该属性查询BackgroundWorker实例是否正在运行异步操作,如果 BackgroundWorker 正在运行异步操作,则为true,否则为false。
BackgroundWorker类包含3个事件,在事件处理程序中可进行异步操作辅助代码编写和同用户界面信息交互。
publiceventDoWorkEventHandler DoWork;
publiceventProgressChangedEventHandler ProgressChanged;
publiceventRunWorkerCompletedEventHandler RunWorkerCompleted;
DoWork事件处理程序用来调用辅助方法进行实际处理操作,由于该事件处理程序在不同于UI的线程上执行,因此需要确保在 DoWork 事件处理程序中不操作任何用户界面对象。如果辅助方法需要参数支持,可以通过RunWorkerAsync方法传入,在 DoWork 事件处理程序中,通过 DoWorkEventArgs.Argument 属性提取该参数。在异步操作期间,可以通过 ProgressChanged事件处理程序获取异步操作进度信息,通过RunWorkerCompleted 事件处理程序获取异步操作结果信息,在ProgressChanged和RunWorkerCompleted的事件处理程序中可以安全的同用户界面进行通信。
Runable和thread的区别
在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口; Thread类是在java.lang包中定义的。一个类只要继承了Thread类同时覆写了本类中的 run()方法就可以实现多线程操作了,但是一个类只能继承一个父类,这是此方法的局限, 下面看例子: package org.thread.demo; class MyThread extends Thread{ private String name; public MyThread(String name) { super(); this.name = name; } public void run(){ for(int i=0;i<10;i++){ System.out.println("线程开始:"+this.name+",i="+i); } } } package org.thread.demo; public class ThreadDemo01 { public static void main(String[] args) { MyThread mt1=new MyThread("线程a"); MyThread mt2=new MyThread("线程b"); // thread1,thread2,按顺序进行 mt1.run(); mt2.run(); } } 但是,此时结果很有规律,先第一个对象执行,然后第二个对象执行,并没有相互运行。在JDK的文档中可以发现,一旦调用start()方法,则会通过JVM找到run()方法。下面启动 start()方法启动线程: package org.thread.demo; public class ThreadDemo01 { public static void main(String[] args) { MyThread mt1=new MyThread("线程a"); MyThread mt2=new MyThread("线程b"); //乱序进行 mt1.start(); mt2.start(); } }; 这样程序可以正常完成交互式运行。那么为啥非要使用start()方法启动多线程呢? 在JDK的安装路径下,src.zip是全部的java源程序,通过此代码找到Thread中的start()方法的定义,可以发现此方法中使用了private native void start0();其中native关键字表示可以调用操作系统的底层函数,那么这样的技术成为JNI技术(java Native Interface) ·Runnable接口 在实际开发中一个多线程的操作很少使用Thread类,而是通过Runnable接口完成。 public interface Runnable{ public void run(); } 例子: package org.runnable.demo; class MyThread implements Runnable{ private String name; public MyThread(String name) { this.name = name; } public void run(){ for(int i=0;i<100;i++){ System.out.println("线程开始:"+this.name+",i="+i); } } }; 但是在使用Runnable定义的子类中没有start()方法,只有Thread类中才有。此时观察Thread类,有一个构造方法:public Thread(Runnable target) 此构造方法接受Runnable的子类实例,也就是说可以通过Thread类来启动Runnable实现的多 线程。(start()可以协调系统的资源): package org.runnable.demo; import org.runnable.demo.MyThread; public class ThreadDemo01 { public static void main(String[] args) { MyThread mt1=new MyThread("线程a"); MyThread mt2=new MyThread("线程b"); new Thread(mt1).start(); new Thread(mt2).start(); } }
如何使用backgroundWorker进行异步操作
在应用程序中,可能会遇到一些执行耗时的功能操作,比如数据下载、复杂计算及数据库事务等,一般这样的功能会在单独的线程上实现,执行结束后结果显示到用户界面上,这样可避免造成用户界面长时间无响应情况。在.NET 2.0及以后的版本中,FCL提供了BackgroundWorker组件来方便的实现这些功能要求。
组件介绍
BackgroundWorker类位于System.ComponentModel 命名空间中,通过该类在单独的线程上执行操作实现基于事件的异步模式。下面对BackgroundWorker类的主要成员进行介绍。
BackgroundWorker类的第1个主要方法是RunWorkerAsync,该方法提交一个以异步方式启动运行操作的请求,发出请求后,将引发 DoWork 事件,在事件处理程序中开始执行异步操作代码。RunWorkerAsync 方法签名如下,
publicvoidRunWorkerAsync();
publicvoidRunWorkerAsync(Object argument);
如果异步操作需要操作参数,可以将其作为argument参数提供,由于参数类型为Object,因此访问时可能需要进行类型转换。
CancelAsync 方法提交终止异步操作的请求,并将 CancellationPending 属性设置为 true。需要注意的是,CancelAsync 方法是否调用成功,同WorkerSupportsCancellation 属性相关,如果允许取消执行的异步操作,需将WorkerSupportsCancellation 属性设置为true,否则调用该方法将抛出异常。CancelAsync方法不含参数,方法签名如下,
publicvoid CancelAsync();
调用 CancelAsync 方法时,BackgroundWorker的 CancellationPending 属性值将被设置为true,因此在编写单独线程中执行的辅助方法时,代码中应定期检查 CancellationPending 属性,查看是否已将该属性设置为 true,如果为true,应该结束辅助方法的执行。有一点需要注意的是,DoWork 事件处理程序中的代码有可能在发出取消请求时已经完成处理工作,因此,DoWork事件处理程序或辅助方法可能会错过设置CancellationPending属性为true的时机。在这种情况下,即使调用 CancelAsync方法发出了取消异步操作请求,RunWorkerCompleted 事件处理程序中RunWorkerCompletedEventArgs 参数的 Cancelled 标志也不会被设置为 true,这是在多线程编程中经常会出现的竞争条件问题,因此编写代码的时候需要考虑。
在执行异步操作时,如果需要跟踪异步操作执行进度,BackgroundWorker类提供了 ReportProgress 方法,调用该方法将引发 ProgressChanged 事件,通过注册该事件在事件处理程序中获取异步执行进度信息。方法签名如下:
publicvoidReportProgress(int percentProgress);
publicvoidReportProgress(int percentProgress,Object userState);
该方法包含两个版本,percentProgress表示进度百分比,取值为0-100,userState为可选参数表示自定义用户状态。
同CancelAsync 方法一样,BackgroundWorker的WorkerReportsProgress 属性设置为 true时,ReportProgress 方法才会调用成功,否则将引发InvalidOperationException异常。
上面已经提到了BackgroundWorker的3个属性,CancellationPending用来提示操作是否已经取消,WorkerReportsProgress和WorkerSupportsCancellation分别用来设置是否允许进度汇报和进行取消操作。
publicboolCancellationPending { get; }
publicboolWorkerReportsProgress { get; set; }
publicboolWorkerSupportsCancellation { get; set; }
另外一个会用到的属性是IsBusy,
publicbool IsBusy { get; }
通过该属性查询BackgroundWorker实例是否正在运行异步操作,如果 BackgroundWorker 正在运行异步操作,则为true,否则为false。
BackgroundWorker类包含3个事件,在事件处理程序中可进行异步操作辅助代码编写和同用户界面信息交互。
publiceventDoWorkEventHandler DoWork;
publiceventProgressChangedEventHandler ProgressChanged;
publiceventRunWorkerCompletedEventHandler RunWorkerCompleted;
DoWork事件处理程序用来调用辅助方法进行实际处理操作,由于该事件处理程序在不同于UI的线程上执行,因此需要确保在 DoWork 事件处理程序中不操作任何用户界面对象。如果辅助方法需要参数支持,可以通过RunWorkerAsync方法传入,在 DoWork 事件处理程序中,通过 DoWorkEventArgs.Argument 属性提取该参数。在异步操作期间,可以通过 ProgressChanged事件处理程序获取异步操作进度信息,通过RunWorkerCompleted 事件处理程序获取异步操作结果信息,在ProgressChanged和RunWorkerCompleted的事件处理程序中可以安全的同用户界面进行通信。
怎么根据条件停止BackgroundWorker线程,再根据条件再打开线程
怎么根据条件停止BackgroundWorker线程,再根据条件再打开线程
包管理器还原自动下载与通配符相匹配的“最新版本”。版本号的空引号对表示“使用最新可用项”。我们创建的项目可以针对一个或者多个
Framework(比如我们希望创建的可以同时在.NET Framework和.NET
Core上运行),支持的Framework定义在frameworks节点下。如果添加了多个Framework,并不是说最终生成的应用可以同时在这
些Framework中运行,而是说源文件在编译的时候会针对这些Framework生成对应的程序集。对于传统的.NET项目来说,如果我们需要调用某
个API,需要添加所在程序集的引用。对于.NET
Core来说,所有使用到的程序集都被打包成一个NuGet包,所以针对程序集的直接依赖转变成针对某个NuGet包的依赖。针对NuGet的依赖主要有
两种类型,一种是针对所有Framework的,它们会直接定义在dependencies节点下,另一种则是针对某个具体Framework的,
定义为当前Framework节点下的dependencies子节点。对于独立应用,运行时部分指定将支持的
OS,因此可指定要绑定到应用程序的运行时库。
教你如何解决“线程间操作无效: 从不是创建控件的线程访问它”
这个时候程序会卡,当程序员将这些卡代码放进线程(Thread)中后发现当对控件操作时出现“线程间操作无效: 从不是创建控件的线程访问它”异常。 为什么.net不让我们跨线程操作控件,这是有好处的。因为如果你的线程多了,那么当两个线程同时尝试将一个控件变为自己需要的状态时,线程的死锁就会发生。但是难道就是因为这个原因,我们就只能让程序卡着么?当然不是,这里教大家一个解决方案:用BackGroundWorker 这里通过一个实例来告诉大家BackGroundWorker的用法。 首先我们先定义一个BackGroundWorker,大家可以去面板上拖一个,也可以自己手工定义一个。this.backgroundWorker_Combo = new System.ComponentModel.BackgroundWorker();//定义一个backGroundWorkerthis.backgroundWorker_Combo.WorkerSupportsCancellation = true;//设置能否取消任务 this.backgroundWorker_Combo.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker_Combo_DoWork);//让backgroundWorker做的事this.backgroundWorker_Combo.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker_Combo_RunWorkerCompleted);//当backgroundWorker做完后发生的事件 如果是从面板上拖的,那么请在DoWork事件上双击,添加那些你想在背景线程中执行的代码,也就是那些可能会让你卡的代码。 然后再在RunWorkerCompleted事件上双击,添加那些你想往控件里操作的代码。 这里有一个开发实例,讲的是实现类似Google搜索中下拉列表的实现。其思路是在DoWork中搜索数据库,在Completed中将搜出来的东西放进去。 本文需要一个backgroundWorker,一个ComboBox控件 static char x;/**//// /// 接受从DLL搜出来的项目/// private string[] global_ListItem;private void backgroundWorker_Combo_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){//如果数组中有东西,那么加入ComboBox if (global_ListItem.Length>0){this.comboBox_App.Items.Clear();this.comboBox_App.Items.AddRange(global_ListItem);} } private void backgroundWorker_Combo_DoWork(object sender, DoWorkEventArgs e){global_ListItem = Form_Setting.Global_DBC.SimilarFilter(x); //这是一个DLL中的方法,用于查找所有以X打头的项目,并放入一个数组中 } private void comboBox_App_TextChanged(object sender, EventArgs e){//当用户键入一个字母时去数据库查 ComboBox cb = sender as ComboBox;if (cb.Text.Length==1){x = cb.Text[0];} } 那么是不是用Thread就不行呢?其实不是的,.net中也有线程安全的控件访问。
c# 线程间操作无效: 从不是创建控件“”的线程访问它。
楼上已经解释的很清楚了,VS2005以上版本跨线程处理。
在MSDN里面可以找到,关键字:线程安全
委托名可以自己定义,
listBoxInfo 可以换成你的dgList。
(如果你直接执行,那么就是从子线程调用主线程的方法执行你的操作,这样是不允许的。
虽然没人告诉我这是为什么,但是我觉得(很多线程同时调用)那样可能会导致死锁的情况。
举例说,我是主线程,电脑是子线程,我能够控制子线程怎么操作,可是你能让电脑控制我吗?显然不能,也不可能。
那为什么引用就可以呢?引用是什么?
引用就是方法的别名,如果你打过游戏,可以理解这是方法的一个副本。
每个线程创建一个我的副本,那么就可以执行了,不会出现争抢,死锁的情况。)
一楼线程安全代码的解释是这样的:
定义一个委托
创建一个方法
{
如果某一个操作需调用主线程的该方法
给他创建一个该方法的副本,调用该方法的副本执行操作
如果并没有调用主线程操作
直接执行【你需要的操作】
}
如果,你还不能理解,我只能说,I'm sorry.I do my best!
c#窗体 如何在backgroundworker的DoWork中结束这个后台?
你好,BackgroundWorker的DoWork事件的委托签名如下: private void DoWork(object sender, DoWorkeventArgs e) 其中参数e包含了大量信息,同时能够接收使用e.Cancel=true令worker取消任务。 需要在DoWork中取消,应使用e.Cancel=true;return; 需要在外部取消,应:在初始化时令backgroundWorker1.WorkerReportsProgress = true;在外部控制的地方(如按钮事件)backgroundWorker1.CancelAsync();CancelAsync会更改worker的CancellationPending标志,所以在DoWork中应有类似下面的片段判断并退出。 if(backgroundWorker1.CancellationPending) { e.Cancel=true; return;} 最后,在DoWork退出后,如需在外部得知是何种原因导致结束(取消或完成),请在worker的RunWorkerCompleted事件中检查参数e.Cancel属性。
backgroundworker的使用和与thread的区别
backgroundworker与thread的区别如下: 1、BackgroundWorker在内部封装了线程。所以你创建了一个BackgroundWorker,就相当于创建一个线程,并且提供一个方法做为任务由它去执行。 2、在WINDWOS桌面程序中使用线程时,常常会遇到需要跨线程访问线程的情况,因为WINDOWS的界面控件都不是线程安全的,所以不能直接跨线程访问。 3、使用BackgroundWorker时,处理进度显示量容易。 4、当你执行的任务较简单,不需要复杂控制时使用BackgroundWorker,较为方便;当你要执行的任务需要复杂控制(如线程同步)时,要自己 创建线程。
怎么插入完成进度条
1、打开一张单元表,我们需要在完成进度”一列中展示完成的进度。
2、选择要插入进度条的单元格。
3、在菜单栏中选择条件按钮”中的数据条”选项。
4、在数据条”选项中有很多填充方式供我们选择,现在我们选择第一种填充方式。
5、在需要插入进度条的单元格中输入我们希望插入的百分数。
6、我们可以看到单元格中显示出了进度条,这样就完成了单元格插入进度条的操作。
怎样在状态栏中显示进度条
虽然Visual 中的MFC类提供了标准的进度指示器(progress control),但是我们不能在状态栏里直接使用这个,要解决这个问题,可以创建一个可重用类CProgStatusBar,这个类从CStatusBar派生,用来来实现状态条中的进度指示。整个实现过程不是很难,思路是在状态栏创建一个进度指示器控制,把它作为子窗口来对待,然后根据不同的状态来显示或者隐藏进度指示器。
在具体实现CProgStatusBar类的过程中,首先在CProgStatusBar派生类中加了一个CProgressCtrl类型的数据成员--m_wndProgBar,然后重载CstatusBar类的二个重要成员函数:OnCreate()、OnSize(),最后还要在该类中添加一个自定义成员函数OnProgress()。在上述三个函数中, OnCreate()负责在状态栏第一次被创建时接收控制,继而创建进度指示器并将它初始化为一个子窗口,它的实现代码如下:
int CProgStatusBar::OnCreate(LPCREATESTRUCT lpcs)
{
lpcs->style |= WS_CLIPCHILDREN;
VERIFY(CStatusBar::OnCreate(lpcs)==0);
VERIFY(m_wndProgBar.Create(WS_CHILD, CRect(), this, 1));
m_wndProgBar.SetRange(0,100);
return 0;
}
C#中 BackGroundWorker与Thread的区别?
使用Thread ,在多线程编程中经常需要在线程间共享资源。例如,多个线程可能需要访问一个共享数据库,或对一组系统变量进行更新。当多个线程同时竞争共享资源的访问权时,就可能会出现“争用状态”。您可以通过使用“锁”来保护代码的关键部分免受争用状态的损坏。当然这需要通过细致的手动编码来实现.
在.NET Framework 2.0中 BackgroundWorker 组件取代了 System.Threading 命名空间并添加了功能,简化了面向用户的编码难度,可以很好的帮你处理多线程间的调度,保护等方面的问题,通过提供面向对象的线程模型来使您能够快速、方便地创建多线程应用程序。
对于对线程开发, 需要注意:是否使用lock 关键字可以用来确保代码块完成运行,而不会被其他线程中断,是否及时的创建和终止线程,是否使用线程池来管理每一个线程,此外,简单的创建及销毁线程的测试程序是不足以说明该技术的实际应用的.