Background worker with progress bar timing issue
-
I've come across with this progress bar using worker.ReportProgress(). I was hoping to get a real-time progress Bar value from outside Write_Tag method. In this code below, it does seem to have some 1-2 seconds delay before showing the progress bar status. Any suggesion?
private void InitializeProgressBars()
{
for (int i = 0; i < DevicePath.Count; i++)
{
progressBar[i] = new ProgressBar();
progressBar[i].Location = new Point(3, 16);
progressBar[i].Size = new Size(605, 31);
progressBar[i].Maximum = 100;
}gbProgressStatus0.Controls.Add(progressBar\[0\]); gbProgressStatus1.Controls.Add(progressBar\[1\]); gbProgressStatus2.Controls.Add(progressBar\[2\]); gbProgressStatus3.Controls.Add(progressBar\[3\]);
}
private void InitializeBackgroundWorkers()
{
for (var f = 0; f < DevicePath.Count; f++)
{
bw[f] = new BackgroundWorker();
bw[f].WorkerReportsProgress = true;
bw[f].WorkerSupportsCancellation = true;switch (f) { case 0: { bw\[f\].DoWork += new DoWorkEventHandler(BackgroundWorkerFilesDoWork0); bw\[f\].RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerFilesRunWorkerCompleted0); break; } case 1: { bw\[f\].DoWork += new DoWorkEventHandler(BackgroundWorkerFilesDoWork1); bw\[f\].RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerFilesRunWorkerCompleted1); break; } case 2: { bw\[f\].DoWork += new DoWorkEventHandler(BackgroundWorkerFilesDoWork2); bw\[f\].RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerFilesRunWorkerCompleted2); break; } case 3: { bw\[f\].DoWork += new DoWorkEventHandler(BackgroundWorkerFilesDoWork3); bw\[f\].RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerFilesRunWorkerCompleted3); break; } } } bw\[0\].ProgressChanged += (sender, e) => { progressBar\[0\].Value = e.ProgressPercentage; }; bw\[1\].ProgressChanged += (sender, e) => { progressBar\[1\].Value = e.ProgressPercentage; }; bw\[2\].ProgressChanged += (sender, e) => { progressBar\[2\].Value = e.ProgressPercentage; }; bw\[3\].ProgressChanged += (sender, e) => { progressBar\[3\].Value = e.ProgressPercent
-
I've come across with this progress bar using worker.ReportProgress(). I was hoping to get a real-time progress Bar value from outside Write_Tag method. In this code below, it does seem to have some 1-2 seconds delay before showing the progress bar status. Any suggesion?
private void InitializeProgressBars()
{
for (int i = 0; i < DevicePath.Count; i++)
{
progressBar[i] = new ProgressBar();
progressBar[i].Location = new Point(3, 16);
progressBar[i].Size = new Size(605, 31);
progressBar[i].Maximum = 100;
}gbProgressStatus0.Controls.Add(progressBar\[0\]); gbProgressStatus1.Controls.Add(progressBar\[1\]); gbProgressStatus2.Controls.Add(progressBar\[2\]); gbProgressStatus3.Controls.Add(progressBar\[3\]);
}
private void InitializeBackgroundWorkers()
{
for (var f = 0; f < DevicePath.Count; f++)
{
bw[f] = new BackgroundWorker();
bw[f].WorkerReportsProgress = true;
bw[f].WorkerSupportsCancellation = true;switch (f) { case 0: { bw\[f\].DoWork += new DoWorkEventHandler(BackgroundWorkerFilesDoWork0); bw\[f\].RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerFilesRunWorkerCompleted0); break; } case 1: { bw\[f\].DoWork += new DoWorkEventHandler(BackgroundWorkerFilesDoWork1); bw\[f\].RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerFilesRunWorkerCompleted1); break; } case 2: { bw\[f\].DoWork += new DoWorkEventHandler(BackgroundWorkerFilesDoWork2); bw\[f\].RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerFilesRunWorkerCompleted2); break; } case 3: { bw\[f\].DoWork += new DoWorkEventHandler(BackgroundWorkerFilesDoWork3); bw\[f\].RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerFilesRunWorkerCompleted3); break; } } } bw\[0\].ProgressChanged += (sender, e) => { progressBar\[0\].Value = e.ProgressPercentage; }; bw\[1\].ProgressChanged += (sender, e) => { progressBar\[1\].Value = e.ProgressPercentage; }; bw\[2\].ProgressChanged += (sender, e) => { progressBar\[2\].Value = e.ProgressPercentage; }; bw\[3\].ProgressChanged += (sender, e) => { progressBar\[3\].Value = e.ProgressPercent
Blubbo wrote:
Any suggesion?
It seems to do an update only twice?
int status = tag_device0.Write_Tag(0, writeDat, en_statusDat, pb);
worker.ReportProgress(pb.Value);
if (ReadTag)
{
worker.ReportProgress(0);
byte[] tagData = new byte[1024];
tag5_device0.Read_Tag(0, 0, tagData .Length, ref tagData , pb);
worker.ReportProgress(pb.Value);
}FWIW; the more often you report progress, the longer it'll take to complete the task.
Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^]
-
I've come across with this progress bar using worker.ReportProgress(). I was hoping to get a real-time progress Bar value from outside Write_Tag method. In this code below, it does seem to have some 1-2 seconds delay before showing the progress bar status. Any suggesion?
private void InitializeProgressBars()
{
for (int i = 0; i < DevicePath.Count; i++)
{
progressBar[i] = new ProgressBar();
progressBar[i].Location = new Point(3, 16);
progressBar[i].Size = new Size(605, 31);
progressBar[i].Maximum = 100;
}gbProgressStatus0.Controls.Add(progressBar\[0\]); gbProgressStatus1.Controls.Add(progressBar\[1\]); gbProgressStatus2.Controls.Add(progressBar\[2\]); gbProgressStatus3.Controls.Add(progressBar\[3\]);
}
private void InitializeBackgroundWorkers()
{
for (var f = 0; f < DevicePath.Count; f++)
{
bw[f] = new BackgroundWorker();
bw[f].WorkerReportsProgress = true;
bw[f].WorkerSupportsCancellation = true;switch (f) { case 0: { bw\[f\].DoWork += new DoWorkEventHandler(BackgroundWorkerFilesDoWork0); bw\[f\].RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerFilesRunWorkerCompleted0); break; } case 1: { bw\[f\].DoWork += new DoWorkEventHandler(BackgroundWorkerFilesDoWork1); bw\[f\].RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerFilesRunWorkerCompleted1); break; } case 2: { bw\[f\].DoWork += new DoWorkEventHandler(BackgroundWorkerFilesDoWork2); bw\[f\].RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerFilesRunWorkerCompleted2); break; } case 3: { bw\[f\].DoWork += new DoWorkEventHandler(BackgroundWorkerFilesDoWork3); bw\[f\].RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerFilesRunWorkerCompleted3); break; } } } bw\[0\].ProgressChanged += (sender, e) => { progressBar\[0\].Value = e.ProgressPercentage; }; bw\[1\].ProgressChanged += (sender, e) => { progressBar\[1\].Value = e.ProgressPercentage; }; bw\[2\].ProgressChanged += (sender, e) => { progressBar\[2\].Value = e.ProgressPercentage; }; bw\[3\].ProgressChanged += (sender, e) => { progressBar\[3\].Value = e.ProgressPercent
(This looks like Windows Forms vs. WPF.) In the
...DoWork_n_()
method you create a localProgressBar
that is passed to theWrite_Tag
andRead_Tag
methods. There's not a tight linkage between thatProgressBar
and the one thatReportProgress()
is updating, so the one that is actually visible is not updated very often. If theWrite_Tag
andRead_Tag
methods aren't careful to deal with possible cross-thread updating of theProgressBar
passed to them, then you're kind of out-of-luck. It doesn't appear that there's an event on theProgressBar
that could be used to redirect the updates to the.Value
to use theworker.ReportProgress(..)
. If theWrite_Tag
andRead_Tag
methods are dealing with the cross-thread updating correctly, then you can pass the visibleProgressBar
into theBackgroundWorker
with the argument to theRunWorkerAsync(progressBar[_n_])
and use theReportProgress()
when updating directly in the worker, and pass it into theWrite_Tag
andRead_Tag
methods, counting on them to "do the right thing" when they update it. Something like:private void InitializeProgressBars()
{
for (int i = 0; i < DevicePath.Count; i++)
{
progressBar[i] = new ProgressBar();
progressBar[i].Location = new Point(3, 16);
progressBar[i].Size = new Size(605, 31);
progressBar[i].Maximum = 100;
}gbProgressStatus0.Controls.Add(progressBar[0]);
gbProgressStatus1.Controls.Add(progressBar[1]);
gbProgressStatus2.Controls.Add(progressBar[2]);
gbProgressStatus3.Controls.Add(progressBar[3]);
}private void InitializeBackgroundWorkers()
{
for (var f = 0; f < DevicePath.Count; f++)
{
bw[f] = new BackgroundWorker();
bw[f].WorkerReportsProgress = true;
bw[f].WorkerSupportsCancellation = true;switch (f) { case 0: { bw\[f\].DoWork += new DoWorkEventHandler(BackgroundWorkerFilesDoWork0); bw\[f\].RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerFilesRunWorkerCompleted0); break; } case 1: { bw\[f\].DoWork += new DoWorkEventHandler(BackgroundWorkerFilesDoWork1); bw\[f\].RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerFilesRunWorkerCompleted1);
-
(This looks like Windows Forms vs. WPF.) In the
...DoWork_n_()
method you create a localProgressBar
that is passed to theWrite_Tag
andRead_Tag
methods. There's not a tight linkage between thatProgressBar
and the one thatReportProgress()
is updating, so the one that is actually visible is not updated very often. If theWrite_Tag
andRead_Tag
methods aren't careful to deal with possible cross-thread updating of theProgressBar
passed to them, then you're kind of out-of-luck. It doesn't appear that there's an event on theProgressBar
that could be used to redirect the updates to the.Value
to use theworker.ReportProgress(..)
. If theWrite_Tag
andRead_Tag
methods are dealing with the cross-thread updating correctly, then you can pass the visibleProgressBar
into theBackgroundWorker
with the argument to theRunWorkerAsync(progressBar[_n_])
and use theReportProgress()
when updating directly in the worker, and pass it into theWrite_Tag
andRead_Tag
methods, counting on them to "do the right thing" when they update it. Something like:private void InitializeProgressBars()
{
for (int i = 0; i < DevicePath.Count; i++)
{
progressBar[i] = new ProgressBar();
progressBar[i].Location = new Point(3, 16);
progressBar[i].Size = new Size(605, 31);
progressBar[i].Maximum = 100;
}gbProgressStatus0.Controls.Add(progressBar[0]);
gbProgressStatus1.Controls.Add(progressBar[1]);
gbProgressStatus2.Controls.Add(progressBar[2]);
gbProgressStatus3.Controls.Add(progressBar[3]);
}private void InitializeBackgroundWorkers()
{
for (var f = 0; f < DevicePath.Count; f++)
{
bw[f] = new BackgroundWorker();
bw[f].WorkerReportsProgress = true;
bw[f].WorkerSupportsCancellation = true;switch (f) { case 0: { bw\[f\].DoWork += new DoWorkEventHandler(BackgroundWorkerFilesDoWork0); bw\[f\].RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerFilesRunWorkerCompleted0); break; } case 1: { bw\[f\].DoWork += new DoWorkEventHandler(BackgroundWorkerFilesDoWork1); bw\[f\].RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerFilesRunWorkerCompleted1);
I have came up with a solution before I saw this reply with Action. I placed a new method in the class (same class with Read_Tag method in it). Works gracefully!
void UpdateProgressBar(ProgressBar pb, int value)
{
if (pb.InvokeRequired)
{
Action action = new Action(UpdateProgressBar);
object[] obj = new object[] { pb, value };
pb.BeginInvoke(action, obj);
}
else
pb.Value = value;
}public int tag5_device0.Read_Tag(, ProgressBar pb)
{
//code snippetfor (int i = 0; i < 44; i++)
{
UpdateProgressBar(pb, i);
} -
I have came up with a solution before I saw this reply with Action. I placed a new method in the class (same class with Read_Tag method in it). Works gracefully!
void UpdateProgressBar(ProgressBar pb, int value)
{
if (pb.InvokeRequired)
{
Action action = new Action(UpdateProgressBar);
object[] obj = new object[] { pb, value };
pb.BeginInvoke(action, obj);
}
else
pb.Value = value;
}public int tag5_device0.Read_Tag(, ProgressBar pb)
{
//code snippetfor (int i = 0; i < 44; i++)
{
UpdateProgressBar(pb, i);
}I think you should just create the delegate once as it doesn't change. And the
BeginInvoke
's second argument isparams
so it will assemble the object array automatically, so this might be easier to read:private static Action<ProgressBar, int> UpdateProgressBarAction = UpdateProgressBar; private static void UpdateProgressBar(ProgressBar pb, int value) { if (pb.InvokeRequired) { pb.BeginInvoke(UpdateProgressBarAction, pb, value); } else pb.Value = value; }
You could even use a lambda to define this self-referentially to avoid the separate
UpdateProgressBarAction
:private static Action<ProgressBar, int> UpdateProgressBar = (ProgressBar pb, int value) => { if (pb.InvokeRequired) { pb.BeginInvoke(UpdateProgressBar, pb, value); } else pb.Value = value; };
-
I think you should just create the delegate once as it doesn't change. And the
BeginInvoke
's second argument isparams
so it will assemble the object array automatically, so this might be easier to read:private static Action<ProgressBar, int> UpdateProgressBarAction = UpdateProgressBar; private static void UpdateProgressBar(ProgressBar pb, int value) { if (pb.InvokeRequired) { pb.BeginInvoke(UpdateProgressBarAction, pb, value); } else pb.Value = value; }
You could even use a lambda to define this self-referentially to avoid the separate
UpdateProgressBarAction
:private static Action<ProgressBar, int> UpdateProgressBar = (ProgressBar pb, int value) => { if (pb.InvokeRequired) { pb.BeginInvoke(UpdateProgressBar, pb, value); } else pb.Value = value; };