Reputation: 10247
I simply want a nondeterministic progressbar that becomes visible and shows some "activity" to indicate a query is running, and then, when the query is through, goes back to being invisible. Seems simple enough; but with this code:
try
{
Cursor.Current = Cursors.WaitCursor;
progressBarChanges.Value = 50;
progressBarChanges.Step = 20;
progressBarChanges.Visible = true;
... // the meat of the code, where the query is being done, elided
} finally
{
progressBarChanges.Visible = false;
Cursor.Current = Cursors.Default;
}
...the progress bar never displays, even though the query takes awhile to run. The progress bar is on a DGV. I realize my progress code is a bit lame, but first things first - I just want the darned thing to show something for starters.
I am setting the progressBar to visible way before I'm calling the BackgroundWorker proc that runs the query:
progressBarChanges.Value = 50;
progressBarChanges.Step = 20;
progressBarChanges.Visible = true;
. . .
if (args.KeyCode == Keys.Enter)
{
if (ValidEntryForCRID(textBoxID.Text))
{
RetrieveAndBindPlatypusData();
var tb = (TextBox)Controls.Find("textBoxDuckbill", true).First();
if (tb != null)
{
tb.Focus();
}
if ((!string.IsNullOrWhiteSpace(textBoxID.Text)) &&
(backgroundWorkerShowChanges.IsBusy != true))
{
backgroundWorkerShowChanges.RunWorkerAsync();
}
. . .
...yet the progressBar is never becoming visible (unless I never set it back to visible = false after the DGV's DataSource is assigned the OracleDateTable value of the returned query/result set). If I comment that out, it then (belatedly) finally shows up, apparently thinking (erroneously) "better late than never."
Is there a way to force Windows to "pay attention" to the "progressBarChanges.Visible = true;" line right away? Something like a .ProcessMessages() or this.Refresh or...???
Upvotes: 1
Views: 7409
Reputation: 10247
This is how I got it to work:
I enable the ProgressBar just before the BackgroundWorker call:
progressBarChanges.Visible = true;
backgroundWorkerShowChanges.RunWorkerAsync();
The BackgroundWorker code gets the OracleDataTable from the DB:
private void backgroundWorkerShowChanges_DoWork(object sender, System.ComponentModel.DoWorkEventArgs args)
{
holdChanges = GetChangesMade(textBoxID.Text);
}
The BackgroundWorker's "completed" event updates the UI:
private void backgroundWorkerShowChanges_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs args)
{
PopulateChangesGrid();
}
In PopulateChangesGrid(), after assigning the OracleDataTable object to the DGV, I set the Progress bar invisible:
private void PopulateChangesGrid()
{
dgvPlatypi.DataSource = holdChanges;
progressBarChanges.Visible = false;
}
It works like a charm (<-- not necessarily a reference to Windows 8 "Metro" charms).
Upvotes: 0
Reputation: 67075
This is happening because you are not giving the UI thread time to update. You are updating to visible and immediately running your code. The code should run on a background thread and send update messages.
To elaborate:
When you set the Visible property, the UI thread does not actually update until the end of that current logic. So, what is happening is this:
What you want is:
Then this:
Then this:
A Task or Backgroundworker should be pretty easy to implement this with.
UPDATE FOR CODE TO SHOW CONSTANT SCROLL
I believe you are only missing that the progressbar's style should be ProgressBarStyle.Marquee
. If you already are offloading the work to a backgroundworker, then the rest should just work
public Form1()
{
InitializeComponent();
this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
progressBar1.Enabled = progressBar1.Visible = false;
progressBar1.Style = ProgressBarStyle.Marquee;
}
private void button1_Click(object sender, EventArgs e)
{
progressBar1.Visible = true;
progressBar1.Enabled = true;
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
System.Threading.Thread.Sleep(10000);
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
progressBar1.Visible = progressBar1.Enabled = false;
}
Upvotes: 7