Reputation: 7177
I am trying to create a thread that contains a form progress bar (just a GIF image).
I have called StartProgress()
right before a large method. Basically when the thread starts it loads up the ProgressBar form (which I want to show all the time, and just hide it when it's not needed) and with ProgressActive
set to true, it should display the form until ProgressActive
is false, then the form should be hidden (until progress is active again). Here is what I have so far, but it freezes up on me :(
public static string ProgressInfo="Test";
public static bool ProgressActive=true;
public static bool ThreadStarted = false;
public static void StartProgress()
{
while (!ThreadStarted)
{
Thread t = new Thread(new ThreadStart(Progress));
ThreadStarted = true;
t.Start();
}
}
public static void Progress()
{
while (ThreadStarted)
{
LoadingBar lb = new LoadingBar();
lb.Show();
lb.TopMost = true;
while (ThreadStarted)
{
if (ProgressActive)
{
lb.Visible = true;
lb.lblLoadingStatus.Text = ProgressInfo;
}
else
{
lb.Visible = false;
}
Thread.Sleep(1000);
}
}
}
EDIT: I am trying to do this within a static class.
Upvotes: 1
Views: 336
Reputation: 5318
The freezing is due to the fact you are trying to change your progress bar contained on the UI thread from your worker thread. I would recommend raising an event from within your worker Progress function to a handler on the UI thread. You will need to marshall the call to the handler on the thread as below.
private object _lock = new object(); //should have class scope
private void ShowProgressControl(EventArgs e)
{
if (this.InvokeRequired)
{
lock (_lock)
{
EventHandler d = new EventHandler(ShowProgressControl);
this.Invoke(d, new object[] { e });
return;
}
}
else
{
//Show your progress bar.
}
}
Enjoy!
Upvotes: 1
Reputation: 18286
You should create the progress bar on the main thread.
Make sure your heavy procedure runs from another thread.
Upvotes: 0
Reputation: 17556
Is there any reason for not using BackgroundWorker if using .NET 2.0 or higher?
The reason I am saying that is because BackgroundWorker is event based, so it exposes an event like ProgressChanged which can reduce the overall size of your code.
Upvotes: 4
Reputation: 48949
The problem is that you need a message loop for any UI element to work correctly. Since you are creating the form in a worker thread then there is no message loop running. To create the message loop you have to call Application.Run
or Form.ShowDialog
both of which are blocking calls. Obviously that solution would hang up your worker thread.
The best thing to do is to create a separate thread dedicated to running the message loop and which can safely handle forms and controls. Have the worker thread periodically publish progress information to a variable that can be shared between the worker thread and the UI thread. Then have the UI thread periodically poll (using System.Windows.Form.Timer) that shared variable and update the UI accordingly.
As a side note, I would avoid using Control.Invoke
or Control.BeginInvoke
to push the progress information to the UI thread. You situation seems to warrant the polling approach instead. The reasons for preferring polling over pushing are:
Control.Invoke
imposes.Upvotes: 1