开发者

Need help with threading -C# Windows Forms

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 = ne开发者_如何学JAVAw 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.


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.


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!


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).


You should create the progress bar on the main thread.

Make sure your heavy procedure runs from another thread.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜