BackgroundWorker_ProgressChanged 从另一个调用 Class 未更新进度条
BackgroundWorker_ProgressChanged Invoked From Another Class Not Updating Progress Bar
更新并改进了详细的源代码
上下文:
我正在使用 MVC 架构构建 Winforms 应用程序。我的视图包含一个搜索按钮、一个 ProgressBar 和 BackgroundWorker 控件。
活动
this.wrkBackgroundSearch.WorkerReportsProgress = true;
this.wrkBackgroundSearch.WorkerSupportsCancellation = true;
this.wrkBackgroundSearch.DoWork += new System.ComponentModel.DoWorkEventHandler(this.wrkBackgroundSearch_DoWork);
this.wrkBackgroundSearch.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.wrkBackgroundSearch_RunWorkerCompleted);
this.wrkBackgroundSearch.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.wrkBackgroundSearch_ProgressChanged);
BackgroundWorker (wrkBackgrounSearch) 的 DoWork 事件:
private void wrkBackgroundSearch_DoWork(object sender, DoWorkEventArgs e)
{
BatchReaderController backgroundCnt = new BatchReaderController();
BackgroundWorker worker = sender as BackgroundWorker;
IDictionary<int, object> args = (IDictionary<int, object>)e.Argument;
//Breaking the arg list down
Int32 docType = (Int32)args[docTypeArgKey];
Int32 chosenSearchElement = (Int32)args[searchElementArgKey];
Int32 environment = (Int32)args[environmentArgKey];
try
{
e.Result = backgroundCnt.PerformSearch(docType, chosenSearchElement, environment, criteria, isFilenameSearch, worker, totalFileCount, directoriesToSearch, fileNameMask, xPath);
}
catch (Exception ex)
{
this.ShowError(ex.Message, "Error while searching", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
我也有这个活动:
private void wrkBackgroundSearch_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
prgSearchProgress.Value = e.ProgressPercentage;
}
最后,在自定义 BatchReaderController 对象的 PerformSearch 方法中,我有 PerformXPathSearch 方法。 (这是在后台运行的 I/O-intensive 操作,应该提供异步更新。)
private IList<BatchFileData> PerformXPathSearch(IList<String> uncPaths, Int32 docType, Int32 searchElement, String searchCriteria, BackgroundWorker worker, Int64 totalFileCount, String inputFileMask, String inputXPathQuery)
{
Int64 numberFilesSearched = 0;
IList<BatchFileData> searchResults = new List<BatchFileData>();
//Validate inputs
//Look in each drive that was input
foreach (String networkPath in uncPaths)
{
DirectoryInfo dir;
FileInfo[] files = null;
try
{
dir = new DirectoryInfo(networkPath);
}
catch (Exception ae)
{
throw new Exception("Bad directory path: " + ae.Message, ae);
}
if (!dir.Exists)
{
continue;
}
try
{
files = dir.GetFiles(inputFileMask, SearchOption.TopDirectoryOnly);
}
catch (Exception ae)
{
throw new Exception("Invalid filename mask: " + filenameMask, ae);
}
foreach (FileInfo file in files)
{
numberFilesSearched++;
Boolean shouldOpenFile = DetermineWhetherToOpenFile(file.CreationTime);
XmlDocument xmlDoc;
XPathNavigator nav;
XPathNavigator searchNode;
DataSet xmlAsDataSet;
if (!shouldOpenFile)
{
Int32 percentComplete = CalculatePercentComplete(totalFileCount, numberFilesSearched);
worker.ReportProgress(percentComplete, searchResults.Count);
continue;
}
try
{
using (FileStream fs = file.OpenRead())
{
xmlDoc = new XmlDocument();
xmlDoc.Load(fs);
}
}
catch (UnauthorizedAccessException uae)
{
throw new UnauthorizedAccessException("Unable to read path to file: " + file.FullName, uae);
}
nav = xmlDoc.CreateNavigator();
try
{
searchNode = nav.SelectSingleNode(inputXPathQuery);
}
catch (ArgumentException ae)
{
throw new ArgumentException("Argument Exception performing node select: " + xpathQuery, ae);
}
catch (XPathException xpe)
{
throw new XPathException("Xpath error while performing node select: " + xpathQuery, xpe);
}
//If search results returns criteria success, add this data set to the list for display.
if (searchNode != null)
{
//Capture data for later processing
}
Int32 percentageComplete = CalculatePercentComplete(totalFileCount, numberFilesSearched);
worker.ReportProgress(percentageComplete, searchResults.Count);
}
}
return searchResults;
}
计算完成百分比
private Int32 CalculatePercentComplete(Int64 totalFileCount, Int64 numFoldersSearched)
{
Int32 percentAsInt;
float searchPercent;
searchPercent = numFoldersSearched / totalFileCount;
try
{
percentAsInt = Convert.ToInt32(searchPercent);
}
catch (OverflowException oe)
{
throw new OverflowException("Error getting percent complete: " + oe.Message, oe);
}
if ((percentAsInt < 0) || (percentAsInt > 100))
{
throw new ArithmeticException("Invalid percentage: " + percentAsInt);
}
return percentAsInt;
}
问题:
测试时,我的 ProgressBar 没有收到更新,即使在单步执行代码时,ProgressChanged 事件被触发。
在检查 Whosebug 上的线程后,在 ProgressChanged 事件中,我还尝试了以下迭代:
private void wrkBackgroundSearch_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
prgSearchProgress.Invoke(new PerformProgrssUpdate(this.DisplaySearchProgress),
new object[]{e.ProgressPercentage});
//if (prgSearchProgress.InvokeRequired)
//{
// prgSearchProgress.Invoke();
//}
}
private void DisplaySearchProgress(Int32 percentComplete)
{
prgSearchProgress.Value = percentComplete;
}
public delegate void PerformProgrssUpdate(Int32 percentComplete);
注意另一个解决方案的注释掉的尝试。搜索操作将成功完成,当搜索操作完成时,ProgressBar 控件的值更新为 (1/n)% complete,因为搜索完成。
问题
我如何进行这项工作,以便当我的控制器执行 I/O-intense 搜索时,我视图中的进度条会适当更新,以便用户知道正在执行某些功能?
这是经典:
Int32 CalculatePercentComplete(Int64 totalFileCount, Int64 numFoldersSearched)
{
Int32 percentAsInt;
float searchPercent;
searchPercent = numFoldersSearched / totalFileCount;
// searchPercent will be 0.0 here as long as numFoldersSearched < totalFileCount
...
}
searchPercent
是一个 float
这一事实并没有改变 numFoldersSearched/totalFileCount
是一个整数除法。
5L / 6L == 0L
我的问题的解决方案在于我如何确定 Worker 的 ProgressChanged 事件的完成百分比。下面是最终的解决方案:
private Int32 CalculatePercentComplete(Int64 totalFileCount, Int64 numFoldersSearched)
{
Int32 percentAsInt;
Decimal searchPercent;
searchPercent = (Decimal)numFoldersSearched / (Decimal)totalFileCount;
try
{
Decimal x = Math.Round(searchPercent*100, 0, MidpointRounding.ToEven);
percentAsInt = Convert.ToInt32(x);
}
catch (OverflowException oe)
{
throw new OverflowException("Error getting percent complete: " + oe.Message, oe);
}
if ((percentAsInt < 0) || (percentAsInt > 100))
{
throw new ArithmeticException("Invalid percentage: " + percentAsInt);
}
return percentAsInt;
}
更新并改进了详细的源代码
上下文: 我正在使用 MVC 架构构建 Winforms 应用程序。我的视图包含一个搜索按钮、一个 ProgressBar 和 BackgroundWorker 控件。
活动
this.wrkBackgroundSearch.WorkerReportsProgress = true;
this.wrkBackgroundSearch.WorkerSupportsCancellation = true;
this.wrkBackgroundSearch.DoWork += new System.ComponentModel.DoWorkEventHandler(this.wrkBackgroundSearch_DoWork);
this.wrkBackgroundSearch.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.wrkBackgroundSearch_RunWorkerCompleted);
this.wrkBackgroundSearch.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.wrkBackgroundSearch_ProgressChanged);
BackgroundWorker (wrkBackgrounSearch) 的 DoWork 事件:
private void wrkBackgroundSearch_DoWork(object sender, DoWorkEventArgs e)
{
BatchReaderController backgroundCnt = new BatchReaderController();
BackgroundWorker worker = sender as BackgroundWorker;
IDictionary<int, object> args = (IDictionary<int, object>)e.Argument;
//Breaking the arg list down
Int32 docType = (Int32)args[docTypeArgKey];
Int32 chosenSearchElement = (Int32)args[searchElementArgKey];
Int32 environment = (Int32)args[environmentArgKey];
try
{
e.Result = backgroundCnt.PerformSearch(docType, chosenSearchElement, environment, criteria, isFilenameSearch, worker, totalFileCount, directoriesToSearch, fileNameMask, xPath);
}
catch (Exception ex)
{
this.ShowError(ex.Message, "Error while searching", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
我也有这个活动:
private void wrkBackgroundSearch_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
prgSearchProgress.Value = e.ProgressPercentage;
}
最后,在自定义 BatchReaderController 对象的 PerformSearch 方法中,我有 PerformXPathSearch 方法。 (这是在后台运行的 I/O-intensive 操作,应该提供异步更新。)
private IList<BatchFileData> PerformXPathSearch(IList<String> uncPaths, Int32 docType, Int32 searchElement, String searchCriteria, BackgroundWorker worker, Int64 totalFileCount, String inputFileMask, String inputXPathQuery)
{
Int64 numberFilesSearched = 0;
IList<BatchFileData> searchResults = new List<BatchFileData>();
//Validate inputs
//Look in each drive that was input
foreach (String networkPath in uncPaths)
{
DirectoryInfo dir;
FileInfo[] files = null;
try
{
dir = new DirectoryInfo(networkPath);
}
catch (Exception ae)
{
throw new Exception("Bad directory path: " + ae.Message, ae);
}
if (!dir.Exists)
{
continue;
}
try
{
files = dir.GetFiles(inputFileMask, SearchOption.TopDirectoryOnly);
}
catch (Exception ae)
{
throw new Exception("Invalid filename mask: " + filenameMask, ae);
}
foreach (FileInfo file in files)
{
numberFilesSearched++;
Boolean shouldOpenFile = DetermineWhetherToOpenFile(file.CreationTime);
XmlDocument xmlDoc;
XPathNavigator nav;
XPathNavigator searchNode;
DataSet xmlAsDataSet;
if (!shouldOpenFile)
{
Int32 percentComplete = CalculatePercentComplete(totalFileCount, numberFilesSearched);
worker.ReportProgress(percentComplete, searchResults.Count);
continue;
}
try
{
using (FileStream fs = file.OpenRead())
{
xmlDoc = new XmlDocument();
xmlDoc.Load(fs);
}
}
catch (UnauthorizedAccessException uae)
{
throw new UnauthorizedAccessException("Unable to read path to file: " + file.FullName, uae);
}
nav = xmlDoc.CreateNavigator();
try
{
searchNode = nav.SelectSingleNode(inputXPathQuery);
}
catch (ArgumentException ae)
{
throw new ArgumentException("Argument Exception performing node select: " + xpathQuery, ae);
}
catch (XPathException xpe)
{
throw new XPathException("Xpath error while performing node select: " + xpathQuery, xpe);
}
//If search results returns criteria success, add this data set to the list for display.
if (searchNode != null)
{
//Capture data for later processing
}
Int32 percentageComplete = CalculatePercentComplete(totalFileCount, numberFilesSearched);
worker.ReportProgress(percentageComplete, searchResults.Count);
}
}
return searchResults;
}
计算完成百分比
private Int32 CalculatePercentComplete(Int64 totalFileCount, Int64 numFoldersSearched)
{
Int32 percentAsInt;
float searchPercent;
searchPercent = numFoldersSearched / totalFileCount;
try
{
percentAsInt = Convert.ToInt32(searchPercent);
}
catch (OverflowException oe)
{
throw new OverflowException("Error getting percent complete: " + oe.Message, oe);
}
if ((percentAsInt < 0) || (percentAsInt > 100))
{
throw new ArithmeticException("Invalid percentage: " + percentAsInt);
}
return percentAsInt;
}
问题: 测试时,我的 ProgressBar 没有收到更新,即使在单步执行代码时,ProgressChanged 事件被触发。
在检查 Whosebug 上的线程后,在 ProgressChanged 事件中,我还尝试了以下迭代:
private void wrkBackgroundSearch_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
prgSearchProgress.Invoke(new PerformProgrssUpdate(this.DisplaySearchProgress),
new object[]{e.ProgressPercentage});
//if (prgSearchProgress.InvokeRequired)
//{
// prgSearchProgress.Invoke();
//}
}
private void DisplaySearchProgress(Int32 percentComplete)
{
prgSearchProgress.Value = percentComplete;
}
public delegate void PerformProgrssUpdate(Int32 percentComplete);
注意另一个解决方案的注释掉的尝试。搜索操作将成功完成,当搜索操作完成时,ProgressBar 控件的值更新为 (1/n)% complete,因为搜索完成。
问题 我如何进行这项工作,以便当我的控制器执行 I/O-intense 搜索时,我视图中的进度条会适当更新,以便用户知道正在执行某些功能?
这是经典:
Int32 CalculatePercentComplete(Int64 totalFileCount, Int64 numFoldersSearched)
{
Int32 percentAsInt;
float searchPercent;
searchPercent = numFoldersSearched / totalFileCount;
// searchPercent will be 0.0 here as long as numFoldersSearched < totalFileCount
...
}
searchPercent
是一个 float
这一事实并没有改变 numFoldersSearched/totalFileCount
是一个整数除法。
5L / 6L == 0L
我的问题的解决方案在于我如何确定 Worker 的 ProgressChanged 事件的完成百分比。下面是最终的解决方案:
private Int32 CalculatePercentComplete(Int64 totalFileCount, Int64 numFoldersSearched)
{
Int32 percentAsInt;
Decimal searchPercent;
searchPercent = (Decimal)numFoldersSearched / (Decimal)totalFileCount;
try
{
Decimal x = Math.Round(searchPercent*100, 0, MidpointRounding.ToEven);
percentAsInt = Convert.ToInt32(x);
}
catch (OverflowException oe)
{
throw new OverflowException("Error getting percent complete: " + oe.Message, oe);
}
if ((percentAsInt < 0) || (percentAsInt > 100))
{
throw new ArithmeticException("Invalid percentage: " + percentAsInt);
}
return percentAsInt;
}