Using a Progress bar on Form Load

2019-02-15 18:25发布

问题:

Sorry for my Bad English

I am trying to Design a Win Form in C# which will get some Data from a database while It's loading

I want to use a progress bar to show reading data progress

I tried this code (and also many others)

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    this.Show();

    progressBar1.Value = 10;
    int n;

    n = 50;//number of records in DB ,
    double progress = 0;
    double progstep = 25 / n;
    for (int i = 1; i <= n; i++)
    {
        //getting 
        if (progress <= 100)
            progressBar1.Value = (int)progress;
    }

    progressBar1.Value = 35;

    n = 100;//number of records in DB for another data reading from DB ,
    progress = 35;
    progstep = 65 / n;
    for (int i = 1; i <= n; i++)
    {
        //getting data from DB
        dataGridView1.Rows.Add(....);//Adding that data to a datagrid -- parametrs removed.
        progress += progress;
        if (progress <= 100)
            progressBar1.Value = (int)progress;
    }

}

But , Problem is , Form will wait , until data reading progress be completed and I can see just a full progress bar and all data loaded.

What Should I do too fix this?

Thanks

回答1:

Since this is winforms, i'd recommend using a BackgroundWorker.

Basic example:

bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
bgWorker.ProgressChanged += new DoWorkEventHandler(bgWorker_ProgressChanged);
bgWorker.RunWorkerAsync(//pass in object to process)

Which would then kickoff:

private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
     //Do all of your work here
     bgWorker.ReportProgress(); //percent done calculation  
}

Then the Progress changed event would fire to update the UI safely:

private void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
     progressBar.Value = e.ProgressPercentage;
}


回答2:

This is simple mockup to show you how to work with backround worker:

First in your OnLoad create background worker and attach 2 events to it:

var bw = new BackgroundWorker();            
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(WorkCompleted);
bw.DoWork += new DoWorkEventHandler(DoWork);
bw.RunWorkerAsync(data);  //assume data is list of numbers

private void WorkCompleted(object sender, RunWorkerCompletedEventArgs e)  //after work completed remove event handlers and dispose
{
    var bw = (BackgroundWorker)sender;
    bw.RunWorkerCompleted -= WorkCompleted;
    bw.DoWork -= DoWork;
    bw.Dispose();
}

private void DoWork(object sender, DoWorkEventArgs e)
{
    var data = (List<int>)e.Argument;

    foreach (var number in data)
    {
        if (progressBar1.InvokeRequired)
        {
            progressBar1.Invoke((MethodInvoker)delegate { this.ProcessNumber(number); });                    
        }
        else
        {
            ProcessNumber(number);
        }
    }
}

private void ProcessNumber(int i)
{
    progressBar1.PerformStep();

    //do something with i
}


回答3:

Add a backgroundWorker1 to your form.

Then add a YourForm_Shown event

  private void YourForm_Shown(object sender, EventArgs e)
    {
        backgroundWorker1.RunWorkerAsync();
    }

Add on form's contructor after InitializeComponent()

 backgroundWorker1.WorkerReportsProgress = true;
        // This event will be raised on the worker thread when the worker starts
        backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
        // This event will be raised when we call ReportProgress
        backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);

And last add the voids of backgroundWorker1

  void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            // The progress percentage is a property of e
            progressBar1.Value = e.ProgressPercentage;
        }

and

 void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
     {
       for (int i = 1; i <= n; i++)
      {
       //getting data from DB
            dataGridView1.Rows.Add(....);//Adding that data to a datagrid -- parametrs removed.
                    backgroundWorker1.ReportProgress(i);
             // Simulate long task                 
       }
    }


回答4:

Take a look at BackgroundWorker control. During form load invoke

backgroundWorker.RunWorkerAsync();

and override event DoWork to do the dirty work (load data from db) and ProgressChanged to update progress bar. In the event body (lets say the event signature will be something like this):

 private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) {
   var worker = (BackgroundWorker)sender;
   // time consuming operation
   worker.ReportProgress(10, null);
   // ... another stuff
 }


 private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) {
     progressBar.Value = e.ProgressPercentage;
 }