Do not try and work out the time it takes, every computer is different and also depends on the load on your CPU at the time of running.
Here is how to work with the progress bar:
1. Count the number of rows and store in a
float
or
double
variable. This is for the calculation to come as we will be working with decimals.
2. Iterate over the rows counting how many completed
3. Set the progress position to
position / total
(ie: percentage completed). If you want an integer value, then multiply the
result * 100
4. When completed, set the progress to
100%
, just in case of rounding errors
Here is a working example with 100,000 rows:
public partial class Form1 : Form
{
private List<Data> SampleData = new List<Data>();
public Form1()
{
InitializeComponent();
Load += Form1_Load;
button1.Click += button1_Click;
}
private void button1_Click(object sender, EventArgs e)
{
double totalRow = dataGridView1.RowCount;
for (int i = 0; i < dataGridView1.RowCount; i++)
{
progressBar1.Value = (int)(i / totalRow * 100);
dataGridView1.Rows[i].Cells[1].Value =
!(bool)dataGridView1.Rows[i].Cells[1].Value;
}
progressBar1.Value = 100;
}
private void Form1_Load(object sender, EventArgs e)
{
LoadData();
dataGridView1.DataSource = SampleData;
dataGridView1.Columns[0].AutoSizeMode =
DataGridViewAutoSizeColumnMode.None;
dataGridView1.Columns[0].Width = 150;
}
private void LoadData()
{
for (int i = 0; i < 100000; i++)
{
SampleData.Add(new Data {Title = $"A random title # {i:N0}"});
}
}
}
public class Data
{
public string Title { get; set; }
public bool Selected { get; set; }
}
If you want to try it, start a new project, add a
DataGridView
,
Button
, and a
ProgressBar
to a
Form
, then drop the code in the form's code behind, and run.
UPDATE #1
I noticed that you're trying to do it in the background on a seperate thread. I've updated the sample and used Async/Await (
Introduction To Async, Await, And Tasks | Microsoft Learn[
^]), not a
BackgroundWorker
.
public partial class Form1 : Form
{
private List<Data> SampleData = new List<Data>();
public Form1()
{
InitializeComponent();
Load += Form1_Load;
button1.Click += button1_Click;
}
private void button1_Click(object sender, EventArgs e)
{
ProcessAsync().ConfigureAwait(false);
}
private async Task ProcessAsync()
{
double totalRow = dataGridView1.RowCount;
for (int i = 0; i < dataGridView1.RowCount; i++)
{
int index = i;
DispatcherHelper.Execute(() =>
{
progressBar1.Value = (int)(index / totalRow * 100);
dataGridView1.Rows[index].Cells[1].Value =
!(bool)dataGridView1.Rows[index].Cells[1].Value;
});
await Task.Delay(10);
}
DispatcherHelper.Execute(() => progressBar1.Value = 100);
}
private void Form1_Load(object sender, EventArgs e)
{
LoadData();
dataGridView1.DataSource = SampleData;
dataGridView1.Columns[0].AutoSizeMode =
DataGridViewAutoSizeColumnMode.None;
dataGridView1.Columns[0].Width = 150;
}
private void LoadData()
{
for (int i = 0; i < 1000; i++)
{
SampleData.Add(new Data {Title = $"A random title # {i:N0}"});
}
}
}
public class Data
{
public string Title { get; set; }
public bool Selected { get; set; }
}
public static class DispatcherHelper
{
public static void Execute(Action action)
{
if (Application.OpenForms.Count == 0)
{
action.Invoke();
return;
}
try
{
if (Application.OpenForms[0].InvokeRequired)
Application.OpenForms[0]?.Invoke(action);
else
action.Invoke();
}
catch (Exception)
{
}
}
}
The original sample code all ran on the UI thread, so the form was not movable. The Async/await sample code fixes that. When you run the code and hit the button, you can see the
ProgressBar
updating, move the form around.
UPDATE #2
If you want to use a
BackgroundWorker | Microsoft Learn[
^] , then here is another version of the sample code that does:
public partial class Form1 : Form
{
private List<Data> SampleData = new List<Data>();
private BackgroundWorker worker = new BackgroundWorker();
public Form1()
{
InitializeComponent();
Load += Form1_Load;
button1.Click += button1_Click;
worker.WorkerReportsProgress = true;
worker.DoWork += Worker_DoWork;
worker.ProgressChanged += Worker_ProgressChanged;
worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
}
private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
double totalRow = dataGridView1.RowCount;
for (int i = 0; i < dataGridView1.RowCount; i++)
{
dataGridView1.Rows[i].Cells[1].Value =
!(bool)dataGridView1.Rows[i].Cells[1].Value;
Thread.Sleep(10);
worker.ReportProgress((int)(i / totalRow * 100));
}
}
private void Worker_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
private void Worker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Done");
}
private void button1_Click(object sender, EventArgs e)
{
worker.RunWorkerAsync();
}
private void Form1_Load(object sender, EventArgs e)
{
LoadData();
dataGridView1.DataSource = SampleData;
dataGridView1.Columns[0].AutoSizeMode =
DataGridViewAutoSizeColumnMode.None;
dataGridView1.Columns[0].Width = 150;
}
private void LoadData()
{
for (int i = 0; i < 1000; i++)
{
SampleData.Add(new Data {Title = $"A random title # {i:N0}"});
}
}
}
public class Data
{
public string Title { get; set; }
public bool Selected { get; set; }
}
Both the Async/Await & BackgroundWorker samples are valid. To me, IMHO, the Async/Await is cleaner and the modern method.