我讨厌我的第一个问题似乎已被多次回答,但我仍然很难理解如何使用BackgroundWorker调用方法。
我正在使用一系列类和方法处理一个非常大的文本文件。用户选择工具条项后,整个过程开始。顺便说一下,它是这样的:
我认为从用户弹出初始对话框的那一刻起,我就可以将所有内容都包装到BackgroundWorker中,但我现在要做的就是将所有繁重工作完成的方法放入其自己的BackGroundWorker实例中。我也会添加一个ProgressBar,但我认为如果我可以让BackgroundWorker进程滚动,我可以处理它。
从顶部开始(伪代码用于示例目的。为简洁起见省略了很多):
private void ToolStripMenuItem_Click(object sender, EventArgs e)
{
string fileName = openSingleFile.FileName;
processFile(fileName);
}
static public void processFile(string fileName)
{
// many vars/loops exist but not shown
foreach (data in bigData)
{
processItem(stringA, stringB); // <-- this method is where the expensive work is done
x++;
}
}
我已经创建了BackgroundWorker的实例......:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// Things go here
}
...我已经尝试了很多东西,所以我已经回到了上面的演示文稿的开头。
如果我了解BackgroundWorker,我需要执行以下操作:
将上述代码中的processItem(stringA,stringB)替换为:
backgroundWorker1.RunWorkerAsync(processItem(stringA, stringB));
...然后做一些类型的DoWork呼叫? ...然后执行某种类型的RunWorkerCompleted调用?
不知道为什么我的大脑会冻结,但是我花了很多时间才对此感到尴尬而没有结果。任何帮助将不胜感激。如果没有StackOverflow,我很久以前就会成为DOA。
仅供参考:我已经引用了其他SO帖子,MSDN和DotNetPerls示例。我想,我只是在概念上遗漏了一些东西。
答案 0 :(得分:3)
将上述代码中的processItem(stringA,stringB)替换为类似......
不,这就是你遇到麻烦的方式。你绝对想要将processFile()调用移动到worker。在worker中运行processItem()没有可感知的好处,至少在你发布的代码片段中没有。这样做很困难,需要启动多个工人。每个项目一个。每个人都做很少工作的很多工人都不是很健康。如果真的有必要,那么你不想使用BackgroundWorker,你需要一个完全不同的方法,使用几个线程来消耗线程安全队列中的工作包。如果可以避免,不要去那里。
要解决的唯一非常重要的问题是传递processFile()所需的字符串。幸运的是BackgroundWorker.RunWorkerAsync()有一个带有单个对象的重载。传递你的字符串。在DoWork事件处理程序中获取其值,将e.Argument转换回字符串。因此:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
string path = (string)e.Argument;
processFile(path);
}
private void processToolStripMenuItem_Click(object sender, EventArgs e) {
backgroundWorker1.RunWorkerAsync(openSingleFile.FileName);
processToolStripMenuItem.Enabled = false;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
processToolStripMenuItem.Enabled = true;
}
答案 1 :(得分:1)
启动新的后台工作程序是一项昂贵的操作。您不希望为循环的每次迭代启动一个。相反,将整个循环放在单个后台工作者的范围内。
运行ToolStripMenuItem_Click
时,请创建后台工作人员,让processFile
成为DoWork
事件处理程序中的内容。
确保在完成这项工作时,您实际上只是在做这项工作,而不是更新用户界面。您需要将业务逻辑与用户界面分开。如果您想使用当前进度更新UI,请调用ReportProgress
并确保有一个事件处理程序来正确更新UI。
如果您需要在完成工作后更新UI,则可以在RunWorkerCompleted
事件处理程序中执行此操作。如果您正在执行的工作生成一些用于更新UI的结果,请使用后台工作程序的Result
属性将其从DoWork
方法传递给已完成的处理程序。
答案 2 :(得分:1)
BackgroundWorker bgw;
在Load事件或构造函数中:
bgw = new BackgroundWorker();
bgw.WorkerReportsProgress = true;
//bgw.WorkerSupportsCancellation = true;
bgw.DoWork += bgw_DoWork;
bgw.ProgressChanged += bgw_ProgressChanged;
bgw.RunWorkerCompleted += bgw_RunWorkerCompleted;
/
private void ToolStripMenuItem_Click(object sender, EventArgs e)
{
string fileName = openSingleFile.FileName;
bgw.RunWorkerAsync(fileName);
}
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
string fileName = (string)e.Argument;
processFile(fileName);
}
private void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
int Progress = e.ProgressPercentage;
//Update progressbar here
}
private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Job completed
}