Reputation: 199
Trying to update a UI element that updates as DoWork() iterates through every line in a DataTable with a visual progress bar and a textbox that gives the current value. The iteration happens in a background worker and works as expected, as does the progress bar's PerformStep(). However, the TextBox's Text does not change.
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
table = SegmentationLibrary.Core.Utils.GetTableFromQuery(query);
backgroundWorker1.ReportProgress(table.Rows.Count, "Max");
int status = 0;
backgroundWorker1.ReportProgress(status);
table.Columns.Add("seg_rates_id", typeof(Int32));
foreach (DataRow row in table.Rows)
{
row["seg_rates_id"] = 0;
status++;
backgroundWorker1.ReportProgress(status);
Application.DoEvents();
}
}
Progress:
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.UserState != null && e.UserState.ToString() == "Max") {
progressBar.progressBar1.Maximum = e.ProgressPercentage;
}
else if (e.ProgressPercentage == 0)
{
progressBar.progressBar1.Minimum = 0;
progressBar.progressBar1.Style = ProgressBarStyle.Continuous;
progressBar.progressBar1.Value = 1;
progressBar.progressBar1.Step = 1;
progressBar.tbProgress.Text = "Setting initial rate types";
}
else
{
progressBar.progressBar1.PerformStep();
progressBar.tbProgress.Text = "Current at row " + progressBar.progressBar1.Value + " of " + progressBar.progressBar1.Maximum + ", " + progressBar.GetProgressBarPercent().ToString() + "%.";
}
}
Caller:
public void GetFinacData(int year, int month)
{
if (!backgroundWorker1.IsBusy)
{
Application.EnableVisualStyles();
currentMonth = month;
currentYear = year;
query = "SELECT * FROM FINAC_ACTUAL_DATA WHERE fiscal_year = " +
currentYear + " AND fiscal_month = " + currentMonth + ";";
progressBar.Show();
progressBar.progressBarStyle = ProgressBarStyle.Marquee;
progressBar.tbProgress.Text = "Downloading PSGL Extract from database";
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
backgroundWorker1.RunWorkerAsync();
// required for ProgressBar to update?
while (backgroundWorker1.IsBusy)
Application.DoEvents();
workerCompleted.WaitOne();
progressBar.Hide();
}
else
{
MessageBox.Show("Segmentation already in progress.","Error",MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
What's happening:
I tried a few different things, but none of them work. Adding another DoEvents() at the end of ProgressChanged causes a stack overflow. Any ideas?
Upvotes: 0
Views: 772
Reputation:
you could wrap you ui changing code inside this code
this.Invoke(new Action(() => { /* ui changing code */ }));
Upvotes: 1
Reputation: 27944
You can do the updating from the background work, not from your main thread. At this point your main thread is still working and your updates are not processed.
remove
// required for ProgressBar to update?
while (backgroundWorker1.IsBusy)
Application.DoEvents();
workerCompleted.WaitOne();
progressBar.Hide();
then move the:
progressBar.Hide();
to the end of your background worker. And remove all DoEvents from your code. It is not needed to do the updates.
Upvotes: 0