好吧,我一整天都在为此头疼。我对编程还相当陌生,很可能我在这里的整个方法都被误导了。但无论如何。。。所以我有一个简单的gui应用程序,它有一个装满文件夹的列表框,我正在依次对每个文件夹中的每个文件执行操作。这是一个非常长的操作,所以我有两个进度条——每个文件一个,每个文件夹一个。
private void buttonApplySelected_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
double percentToIncrement = 100.0 / Convert.ToDouble(selectedDirList.Count);
double percentComplete = percentToIncrement;
folderProgressBar.Value = 0;
foreach (string dir in selectedDirList)
{
engine = new OEngine.OEngine(dir, backgroundWorker1);
engine.ProcessSelected(processType);
int percentCompleteInt = Convert.ToInt32(percentComplete);
folderProgressBar.Value = percentCompleteInt;
percentComplete += percentToIncrement;
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
fileProgressBar.Value = e.ProgressPercentage;
}
BackgroundWorker本身被传递给引擎,它在引擎处理该文件夹的代码中更新进度。(这可能是我的第一个错误。)UI捕获ProgressChanged事件,并在自己的线程中更新fileProgressBar。
但是folderProgressBar需要在每次通过for循环时更新一次,但它给了我Cross-thread operation not valid: Control 'folderProgressBar' accessed from a thread other than the thread it was created on.
如果我把它移出for循环,它不会在每个文件夹后更新。如果我将所有的UI更新从DoWork函数中移出,并在for循环中调用DoWork函数,它显然不会等待每个文件夹完成,我会得到"工作人员仍然很忙"的异常。
有什么想法吗?
windows窗体的通用解决方案:使用
WindowsFormsSynchronizationContext syncContext = new WindowsFormsSynchronizationContext();
//in the background work or any non UI Thread
//Trigger an update in the GUI thread; one can also use syncContext.Send (depending on the need for syncrhonous or async operation)
syncContext.Post(UpdateGUI, userData);
...
void UpdateGUI(object userData)
{
//update your progress bar
}
If using wpf, declare a variable syncContex.
SynchronizationContext syncContext;
//And when in the UI thread, set the variable's value as
syncContext = SynchronizationContext.Current;
//Then from the non-UI thread,
syncContext.Post(UpdateGUI, userData);