使用改进的详细源代码更新
上下文 我正在使用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密集型操作,应该提供异步更新。)
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事件。
在ProgressChanged事件中检查StackOverflow上的线程之后,我还尝试了以下几次迭代:
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)%完成。
问题 如何使这项工作,以便当我的控制器执行I / O密集型搜索时,我视图中的进度条会相应更新,以便用户知道某些功能正在执行?
答案 0 :(得分:1)
这是经典之作:
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
答案 1 :(得分:0)
我的问题的解决方案在于我如何确定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;
}