How to implement a progress bar in windows forms C#?

雨燕双飞 提交于 2020-01-15 04:38:48

问题


I have my own solution to import monthly sales data in my windows form application. When a user click on import button, the program is actually running but it looks like it's not responding. The process takes a long time about 5 minutes.

So, I'd like to implement a progress bar with status strip label to display as an user interface and let the users know how much the task is done. This is also my first time using a progress bar in my program. So, I read through some tutorials which show how to use it. Some people use progress bar with background worker and timer.

But I don't understand where I should use the solution that I have. In background worker DoWork() event? I don't want to fake it by abusing the progress bar like setting the progressBar.Maximum = 100, progressBar.Value = 0 and as long as the timer is ticking increasing the value by 5. The progress bar must report the actual progress while the program is running.

The following is the solution I am using now to import the data:

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");
        }
    }

Any help will be very much appreciated!


回答1:


Your program has many loops,since it will be difficult to get the increment value and increment the progress bar value in each loop iteration.You could set the progress bar maximum to 100,Then divide 100 by the number of loops you have say X.

So the trick would be to fill the progress bar by this value when each loops completes

and yes you should put this code in backgroundworker's DoWork() otherwise it will freeze the form.Also there is no need for a timer.




回答2:


This is how I have used Progress Bar in my application.

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();
}



回答3:


You can use a ManualResetEvent, Now while you are processing, let the Progressbar Increase until it meets a certain point and wait for a Set.

Example:

you have this 2 fields

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 ++;
}

// This finishes the progress, Now on your actual Work, you have to signal those wait.

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

   reset.Set();

   // Another long process

   reset2.Set();
}


来源:https://stackoverflow.com/questions/18971829/how-to-implement-a-progress-bar-in-windows-forms-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!