2

我有自己的解决方案,可以在我的 Windows 窗体应用程序中导入月度销售数据。当用户单击import按钮时,程序实际上正在运行,但看起来它没有响应。该过程需要很长时间,大约 5 分钟。

所以,我想实现一个带有状态条标签的进度条,以显示为用户界面,让用户知道任务完成了多少。这也是我第一次在我的程序中使用进度条。所以,我通读了一些教程,展示了如何使用它。有些人将进度条与后台工作人员和计时器一起使用。

但我不明白我应该在哪里使用我拥有的解决方案。在后台工作人员DoWork()事件中?我不想通过滥用进度条来伪造它,例如设置 progressBar.Maximum = 100,progressBar.Value = 0 并且只要计时器滴答作响,将值增加 5。进度条必须报告实际进度,而程序正在运行。

以下是我现在用来导入数据的解决方案:

private void btnImport_Click(object sender, EventArgs e)
    {
        if (lsbxBrowsedFiles.Items.Count != 0)
        {
            ArrayList salesHeaderArr = new ArrayList();
            ArrayList salesDetailArr = new ArrayList();

            int i = 0;
            while (i < browsedXmlFileList.Count)
            {
                if (browsedXmlFileList[i].ToUpper().EndsWith("SALESHEADER.XML"))
                {
                    salesHeaderArr.Add(browsedXmlFileList[i]);
                }
                if (browsedXmlFileList[i].ToUpper().EndsWith("SALESDETAIL.XML"))
                {
                    salesDetailArr.Add(browsedXmlFileList[i]);
                }
                i++;
            }

            if (selectedFileIsNotInDestinationFolder(salesHeaderArr, salesDetailArr) == true)
            {
                i = 0;
                while (i < salesHeaderArr.Count)
                {
                    SalesHeader salesHeader = new SalesHeader();
                    string sourceFilePath = salesHeaderArr[i].ToString();
                    readXMLFiles(sourceFilePath, SALES_HEADER);
                    SalesHeader salesCheck = (SalesHeader)salesHeaderList[0];
                    string checkOutletCode = salesCheck.OutletCode;
                    DateTime checkBusDate = salesCheck.BusinessDate.Value;
                    if (SalesHeader.IsThisRowAlreadyImportedInSalesHeader(checkOutletCode, checkBusDate) == false)
                    {
                        salesHeader.ImportSalesHeader(salesHeaderList);
                        salesHeader.CreateImportDataLog(getDestinationFilePath(sourceFilePath),
                            DateTime.Now, salesHeaderList.Count, SALES_HEADER);
                    }
                    else
                    {
                        string errorDate = checkBusDate.ToString("dd MMMM, yyyy");
                        MessageBox.Show("Selected XML File with BusinessDate: " + errorDate + " has been already imported.",
                            "ABC Cafe Import Sales Wizard");
                        MessageBox.Show("Please select a file which has not been imported!",
                            "ABC Cafe Import Sales Wizard");
                        return;
                    }
                    MoveXMLFiletoDestinationFolder(sourceFilePath);
                    i++;
                }
                i = 0;
                while (i < salesDetailArr.Count)
                {
                    SalesDetail salesDetail = new SalesDetail();
                    string sourceFilePath = salesDetailArr[i].ToString();
                    readXMLFiles(sourceFilePath, SALES_DETAIL);
                    SalesDetail salesCheck = (SalesDetail)salesDetailList[0];
                    string checkOutletCode = salesCheck.OutletCode;
                    DateTime checkBusDate = salesCheck.BusinessDate.Value;
                    if (SalesDetail.IsThisRowAlreadyImportedInSalesDetail(checkOutletCode, checkBusDate) == false)
                    {
                        salesDetail.ImportSalesDetail(salesDetailList);
                        salesDetail.GenerateCarryForward(salesDetailList);
                        salesDetail.CalculateImportInventoryBalance(salesDetailList);
                        salesDetail.CreateImportDataLog(getDestinationFilePath(sourceFilePath), DateTime.Now, salesDetailList.Count, SALES_DETAIL);
                    }
                    else
                    {
                        string errorDate = checkBusDate.ToString("dd MMMM, yyyy");
                        MessageBox.Show("Selected XML File with BusinessDate: " + errorDate + " has been already imported.",
                            "ABC Cafe Import Sales Wizard");
                        MessageBox.Show("Please select a file which has not been imported!",
                            "ABC Cafe Import Sales Wizard");
                        return;
                    }
                    MoveXMLFiletoDestinationFolder(sourceFilePath);
                    i++;
                }
                MessageBox.Show("Import has been successfully completed!",
                "ABC Cafe Import Sales Wizard");
                clearListBoxItems();
                lblMessage.Visible = false;
            }
            //Abort the import operation here!
            else
            {
                MessageBox.Show("Please select a file which has not been imported!",
                "ABC Cafe Import Sales Wizard");
                clearListBoxItems();
                lblMessage.Visible = false;
            }
        }
        else
        {
            MessageBox.Show("Please select XML files to import!", 
                "ABC Cafe Import Sales Wizard");
        }
    }

任何帮助将不胜感激!

4

3 回答 3

3

这就是我Progress Bar在我的应用程序中使用的方式。

private void btnNext_Click(object sender, EventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
        worker.WorkerReportsProgress = true;
        worker.ProgressChanged += (se, eventArgs) => {
            this.progressBar.Maximum = 100;
            this.progressBar.Minimum = 0;
            this.progressBar.Value = eventArgs.ProgressPercentage;
            lblStatus.Text = eventArgs.UserState as String;
            lblPercentage.Text = String.Format("Progress: {0} %", eventArgs.ProgressPercentage);
        };

worker.DoWork += (se, eventArgs) => {
    int progress = 0;
    ((BackgroundWorker)se).ReportProgress(progress, "Initializing the files...");

    //Process that takes a long time
    //Formula to calculate Progress Percentage 
    //This is how I calculated for my program. Divide 100 by number of loops you have

    int findPercentage = ((i + 1) * 100) / salesHeaderArr.Count;
    progress = 0;
    progress += findPercentage / 2;

    //Report back to the UI
    string progressStatus = "Importing Sales Header... (" + getSourceFileName(sourceFilePath) + ")";     
    ((BackgroundWorker)se).ReportProgress(progress, progressStatus);

   //After Iterating through all the loops, update the progress to "Complete"
   ((BackgroundWorker)se).ReportProgress(100, "Complete...");
};
worker.RunWorkerCompleted += (se, eventArgs) =>
        {
            //Display smth or update status when progress is completed
            lblStatus.Location = new Point(20, 60);
            lblStatus.Text = "Your import has been completed. \n\nPlease Click 'Finish' button to close the wizard or \n'Back' button to go back to the previous page.";
            lblPercentage.Visible = false;
            progressBar.Visible = false;
            btnBack.Enabled = true;
            btnFinish.Enabled = true;
        };

        worker.RunWorkerAsync();
}
于 2013-11-27T10:37:31.920 回答
1

您的程序有很多循环,因为在每次循环迭代中很难获得增量值并增加进度条值。您可以将进度条最大值设置为 100,然后将 100 除以您所说的循环数 X。

所以诀窍是在每个循环完成时用这个值填充进度条

是的,您应该将此代码放在后台工作人员中,DoWork()否则它将冻结表单。也不需要计时器。

于 2013-09-24T05:12:59.087 回答
-1

您可以使用ManualResetEvent,现在在处理过程中,让Progressbar 增加,直到达到某个点并等待Set。

例子:

你有这 2 个字段

private int progress = 0;
private ManualResetEvent reset = new ManualResetEvent(false); 
// Sets it to unsignalled
private ManualResetEvent reset2 = new ManualResetEvent(false);

while(progress  < 40)
{
   progress ++;
}

reset.WaitOne();

while(progress < 90)
{
   progress ++;
}

reset2.WaitOne();

while(progress < 100)
{
   progress ++;
}

// 这完成了进度,现在在您的实际工作中,您必须向那些等待发出信号。

DoWork()
{
   // long process here. . . .

   reset.Set();

   // Another long process

   reset2.Set();
}
于 2013-09-24T03:47:37.960 回答