C# WinForm多线程。是否使用backgroundWorker?
我有一个简单的应用程序,可以启动一系列数据密集型任务。我对WinForms不是很有经验,我想知道不锁定接口的最佳方法。backgroundWorker是否可以重复使用,或者是否有其他方法可以重复使用C# WinForm多线程。是否使用backgroundWorker?,c#,winforms,multithreading,C#,Winforms,Multithreading,我有一个简单的应用程序,可以启动一系列数据密集型任务。我对WinForms不是很有经验,我想知道不锁定接口的最佳方法。backgroundWorker是否可以重复使用,或者是否有其他方法可以重复使用 谢谢背景工作者将是一个很好的选择 有关更多信息,请查看此处 可以使用backgroundWorker 它的好处是允许您更新进度条并与UI控件交互。(WorkerReportsProgress) 它还有一个取消机制。(工人支持扫描单元) BackgroundWorker是一个线程,它还包括通知同步。例
谢谢背景工作者将是一个很好的选择 有关更多信息,请查看此处
可以使用backgroundWorker 它的好处是允许您更新进度条并与UI控件交互。(
WorkerReportsProgress
)
它还有一个取消机制。(工人支持扫描单元
)
BackgroundWorker是一个线程,它还包括通知同步。例如,如果您想在扫描完成时更新UI,常规的
线程
无法访问UI对象(只有UI线程可以这样做);因此,BackgroundWorker
提供了一个完整的事件处理程序,在操作完成时在UI线程上运行
有关更多信息,请参阅:(MSDN)
和一个简单的示例代码:
var worker = new System.ComponentModel.BackgroundWorker();
worker.DoWork += (sender,e) => Thread.Sleep(60000);
worker.RunWorkerCompleted += (sender,e) => MessageBox.Show("Hello there!");
worker.RunWorkerAsync();
您可以使用BackgroundWorker来满足这些需求。下面是一个示例,
根据任务[长时间运行]完成的百分比更新标签状态
。另外,还有一个示例业务类,它设置了一些值,该值通过ProgressChanged
handler设置回UIDoWork
是编写长时间运行的任务逻辑的地方。在Winforms应用程序上添加标签和backgroundworker组件后,复制粘贴下面的代码并试一试。您可以跨各种处理程序[RunWorkerCompleted,ProgressChanged,DoWork]
进行调试,并查看InitWorker
方法。请注意取消功能
using System.ComponentModel;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form3 : Form
{
private BackgroundWorker _worker;
BusinessClass _biz = new BusinessClass();
public Form3()
{
InitializeComponent();
InitWorker();
}
private void InitWorker()
{
if (_worker != null)
{
_worker.Dispose();
}
_worker = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
_worker.DoWork += DoWork;
_worker.RunWorkerCompleted += RunWorkerCompleted;
_worker.ProgressChanged += ProgressChanged;
_worker.RunWorkerAsync();
}
void DoWork(object sender, DoWorkEventArgs e)
{
int highestPercentageReached = 0;
if (_worker.CancellationPending)
{
e.Cancel = true;
}
else
{
double i = 0.0d;
int junk = 0;
for (i = 0; i <= 199990000; i++)
{
int result = _biz.MyFunction(junk);
junk++;
// Report progress as a percentage of the total task.
var percentComplete = (int)(i / 199990000 * 100);
if (percentComplete > highestPercentageReached)
{
highestPercentageReached = percentComplete;
// note I can pass the business class result also and display the same in the LABEL
_worker.ReportProgress(percentComplete, result);
_worker.CancelAsync();
}
}
}
}
void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
// Display some message to the user that task has been
// cancelled
}
else if (e.Error != null)
{
// Do something with the error
}
}
void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = string.Format("Result {0}: Percent {1}",e.UserState, e.ProgressPercentage);
}
}
public class BusinessClass
{
public int MyFunction(int input)
{
return input+10;
}
}
}
使用System.ComponentModel;
使用System.Windows.Forms;
命名空间Windows窗体应用程序1
{
公共部分类表单3:表单
{
私人背景工人;
BusinessClass _biz=新的BusinessClass();
公共表格3()
{
初始化组件();
InitWorker();
}
私有void InitWorker()
{
如果(_worker!=null)
{
_worker.Dispose();
}
_worker=新的后台工作人员
{
WorkerReportsProgress=true,
WorkerSupportsScanCellation=真
};
_worker.DoWork+=DoWork;
_worker.RunWorkerCompleted+=RunWorkerCompleted;
_worker.ProgressChanged+=ProgressChanged;
_worker.RunWorkerAsync();
}
无效DoWork(对象发送方,DoWorkEventArgs e)
{
int highestPercentageReached=0;
如果(_worker.CancellationPending)
{
e、 取消=真;
}
其他的
{
双i=0.0d;
int=0;
对于(i=0;i最高百分比)
{
highestPercentageReached=完成百分比;
//注意,我也可以传递业务类结果,并在标签中显示相同的结果
_工人报告进度(完成百分比、结果);
_worker.CancelAsync();
}
}
}
}
void RunWorkerCompleted(对象发送方,RunWorkerCompletedEventArgs e)
{
如果(如已取消)
{
//向用户显示任务已完成的消息
//取消
}
否则如果(例如错误!=null)
{
//对这个错误做点什么
}
}
void ProgressChanged(对象发送方,progresschangedventargs e)
{
label1.Text=string.Format(“结果{0}:百分比{1}”,e.UserState,e.ProgressPercentage);
}
}
公务舱
{
公共整数MyFunction(整数输入)
{
返回输入+10;
}
}
}
我会使用backgroundworker。如果您只需要另外一个线程,我会使用后台工作线程,它们非常容易使用,而且大部分的艰苦工作已经完成,为您提供工作完成不同阶段的直接事件。如果您需要该线程在完成其密集工作后与UI元素交互,请使用Backgroundworker。另一个明智的做法是,如果你只是想做一些其他的工作,例如从其他地方填充一些容器数据,这些数据在其他时间或事件中由主UI使用,那么就使用普通线程。用户可以启动各种不同的任务,然后通过entityFramework执行数据库操作。那么,当用户完成任务A后,backgroundworker是否可以再次用于任务B?感谢您的详细回复。我关心的是将“长时间运行的任务逻辑”添加到DoWork事件中。我有许多任务需要运行,将它们全部添加到一个DoWork事件中似乎不太实际。