从另一个类调用BackgroundWorker_ProgressChanged不更新进度条

时间:2015-01-18 20:01:35

标签: c# multithreading backgroundworker

使用改进的详细源代码更新

上下文 我正在使用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密集型搜索时,我视图中的进度条会相应更新,以便用户知道某些功能正在执行?

2 个答案:

答案 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

  ...
}

searchPercentfloat的事实不会改变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;
    }