views:

69

answers:

4

I am trying to create a thread that contains a form progress bar(just a gif image) I have called the 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 its not needed) and with ProgressActive to true, it should display the form until the 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

+4  A: 

is there any reason for not using BackgroundWorker if using .net 2.0 or higher ?

Why i am saying that because BG is event based so it exposes event like ProgressChanged which can reduce all of your code.

saurabh
the reason would be I missed it. still a little lost on using event like ProgressChanged with BG EDIT: Note I am trying to implement this in a complete static class
Spooks
A: 

You should create the progress bar on the main thread.
make sure your heavy procedure runs from other thread.

Itay
+1  A: 

Hi,

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!

Doug
@Doug thanks, but I am using a static class so "this" does not work :(
Spooks
@Spooks - You might want to consider having that static class only for your worker process, have it expose and event and then consume the event in the main form hosting your app on the (UI thread).
Doug
@Doug that sounds like a great idea. Just when I do Thread t = new Thread(new ThreadStart(Progress));Does that create a new worker process (not consuming the UI thread)?
Spooks
@Spooks - yes when you do a Thread t = new Thread(new ThreadStart(Progress)); that creates a new thread which can process work independently of the ui thread that the main form is running on. The method i outlined above will give you maximum flexibility.
Doug
+1  A: 

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:

  • It breaks the tight coupling between the UI and worker threads that Control.Invoke imposes.
  • It puts the responsibility of updating the UI thread on the UI thread where it should belong anyway.
  • The UI thread gets to dictate when and how often the update should take place.
  • There is no risk of the UI message pump being overrun as would be the case with the marshaling techniques initiated by the worker thread.
  • The worker thread does not have to wait for an acknowledgement that the update was performed before proceeding with its next steps (ie. you get more throughput on both the UI and worker threads).
Brian Gideon