I'm trying to have a seperate thread in a WinForms C# application start a background worker which controls a ProgressBar (marquee). The issue is that when i try to set the bar to visible it just does nothing, and i've tried many forms of Invoke but they don't seem to help.
The following method progressBarCycle
is called from a separate thread.
BackgroundWorker backgroundWorker = new BackgroundWorker();
public void progressBarCycle(int duration)
{
backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.WorkerSupportsCancellation = true;
backgroundWorker.RunWorkerAsync(duration);
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
worker.ReportProgress(0);
DateTime end = DateTime.Now.AddMilliseconds((int)e.Argument);
while (DateTime.Now <= end)
{
System.Threading.Thread.Sleep(1000);
}
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (!this.IsHandleCreated)
this.CreateHandle();
statusStrip1.Invoke((MethodInvoker)delegate
{
progressBar1.Visible = false;
});
// if (!this.IsHandleCreated)
// {
// this.CreateHandle();
// if (InvokeRequired) this.Invoke((MethodInvoker)(() => progressBar1.Visible = false));
// else progressBar1.Visible = false;
// }
// else
// if (InvokeRequired) this.Invoke((MethodInvoker)(() => progressBar1.Visible = false));
// else progressBar1.Visible = false;
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (!this.IsHandleCreated)
this.CreateHandle();
statusStrip1.Invoke((MethodInvoker)delegate
{
progressBar1.Visible = true;
});
// if (!this.IsHandleCreated)
// {
// this.CreateHandle();
// if (InvokeRequired) this.Invoke((MethodInvoker)(() => progressBar1.Visible = true));
// else progressBar1.Visible = true;
// }
// else
// if (InvokeRequired) this.Invoke((MethodInvoker)(() => progressBar1.Visible = true));
// else progressBar1.Visible = true;
}
Am I missing something obvious here? The comment sections are other things I've tried.
ProgressChanged
is already raised on the UI thread (via the sync-context); your ProgressChanged
does not need to do that Invoke
- it can manipulate the UI directly (by contrast, DoWork
can absolutely not do that). Perhaps the real problem is that you don't do any worker.ReportProgress(...)
inside the loop - so it only happens once at the start.
Here's a full example:
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
using (var worker = new BackgroundWorker {
WorkerReportsProgress = true })
using (var progBar = new ProgressBar {
Visible = false, Step = 1, Maximum = 100,
Dock = DockStyle.Bottom })
using (var btn = new Button { Dock = DockStyle.Top, Text = "Start" })
using (var form = new Form { Controls = { btn, progBar } })
{
worker.ProgressChanged += (s,a) => {
progBar.Visible = true;
progBar.Value = a.ProgressPercentage;
};
worker.RunWorkerCompleted += delegate
{
progBar.Visible = false;
};
worker.DoWork += delegate
{
for (int i = 0; i < 100; i++)
{
worker.ReportProgress(i);
Thread.Sleep(100);
}
};
btn.Click += delegate
{
worker.RunWorkerAsync();
};
Application.Run(form);
}
}
}
progressBarCycle
from the UI thread. RunWorkerAsync
will
create the new thread for you.backgroundWorker_ProgressChanged
simply call
progressBar1.Visible = true;
. There is no need for Invoke
.progressBar1.Refresh();
.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With