Steven Wilson
Steven Wilson

Reputation: 65

Progress bar on separate thread not updating

In my project i have a Form, like a Task Dialog, that displays on its own thread... This way when the main thread locks up, the Task Dialog's ProgressBar and status can still be updated. The issue im having is that the ProgressBar is not updating. The status text updates, but the ProgressBar doesn't move until right before the Form closes. The Form is being opened in the main thread. Here is my code:

public partial class TaskForm : Form
{
    /// <summary>
    /// Gets or Sets whether the task is cancelable
    /// </summary>
    protected bool Cancelable = true;

    /// <summary>
    /// Returns whether the Task form is already open and running
    /// </summary>
    /// <returns></returns>
    public static bool IsOpen
    {
        get { return (Instance != null && !Instance.IsDisposed); }
    }

    /// <summary>
    /// The task dialog's instance
    /// </summary>
    private static TaskForm Instance;

    /// <summary>
    /// Private constructor... Use the Show() method rather
    /// </summary>
    private TaskForm()
    {
        InitializeComponent();
    }

    /// <summary>
    /// Open and displays the task form.
    /// </summary>
    /// <param name="Parent">The calling form, so the task form can be centered</param>
    public static void Show(Form Parent, string WindowTitle, string InstructionText, string SubMessage, bool Cancelable, ProgressBarStyle Style)
    {
        // Make sure we dont have an already active form
        if (Instance != null && !Instance.IsDisposed)
            throw new Exception("Task Form is already being displayed!");

        // Create new instance
        Instance = new TaskForm();
        Instance.Text = WindowTitle;
        Instance.labelInstructionText.Text = InstructionText;
        Instance.labelContent.Text = SubMessage;
        Instance.Cancelable = Cancelable;
        Instance.progressBar.Style = Style;

        // Hide Cancel
        if (!Cancelable)
        {
            Instance.panelButton.Hide();
            Instance.Padding = new Padding(0, 0, 0, 15);
            Instance.BackColor = Color.White;
        }

        // Set window position to center parent
        double H = Parent.Location.Y + (Parent.Height / 2) - (Instance.Height / 2);
        double W = Parent.Location.X + (Parent.Width / 2) - (Instance.Width / 2);
        Instance.Location = new Point((int)Math.Round(W, 0), (int)Math.Round(H, 0));

        // Run form in a new thread
        Thread thread = new Thread(new ThreadStart(ShowForm));
        thread.IsBackground = true;
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
        Thread.Sleep(100); // Wait for Run to work
    }

    /// <summary>
    /// Closes the Task dialog
    /// </summary>
    public static void CloseForm()
    {
        if (Instance == null || Instance.IsDisposed)
            throw new Exception("Invalid Operation. Please use the Show method before calling any operational methods");

        Instance.Invoke((Action)delegate()
        {
            Instance.Close();
        });
    }

    /// <summary>
    /// Runs the form in a new application, to prevent thread lock
    /// </summary>
    protected static void ShowForm()
    {
        Application.Run(Instance);
    }

    /// <summary>
    /// Updates the instruction text on the task dialog
    /// </summary>
    /// <param name="Message"></param>
    public static void UpdateInstructionText(string Message)
    {
        if (Instance == null || Instance.IsDisposed)
            throw new Exception("Invalid Operation. Please use the Show method before calling any operational methods");

        Instance.Invoke((Action)delegate()
        {
            Instance.labelInstructionText.Text = Message;
        });
    }

    /// <summary>
    /// Updates the detail text above the progress bar
    /// </summary>
    /// <param name="Message"></param>
    public static void UpdateStatus(string Message)
    {
        if (Instance == null || Instance.IsDisposed)
            throw new Exception("Invalid Operation. Please use the Show method before calling any operational methods");

        Instance.Invoke((Action)delegate()
        {
            Instance.labelContent.Text = Message;
        });
    }

    /// <summary>
    /// Updates the progress bar's value
    /// </summary>
    /// <param name="Percent"></param>
    public static void UpdateProgress(int Percent)
    {
        if (Instance == null || Instance.IsDisposed)
            throw new Exception("Invalid Operation. Please use the Show method before calling any operational methods");

        Instance.Invoke((Action)delegate()
        {
            Instance.progressBar.Step = Percent;
            Instance.progressBar.PerformStep();
            Instance.progressBar.Refresh();
        });
    }

    #region Non Static

    private void CancelBtn_Click(object sender, EventArgs e)
    {
        this.DialogResult = DialogResult.Cancel;
        this.Close();
    }

    #endregion
}

It doesnt make sense that text updates when i call the UpdateStatus and UpdateInstructionText methods, but the ProgressBar does not update when calling UpdateProgress. Any help will be appreciated.

Upvotes: 1

Views: 970

Answers (1)

Turbot
Turbot

Reputation: 5227

by looking at your code, you are passing the percentage in UpdateProgress() method in the progressBar.Step property, which the step indicate the amount to increase when PerformStep() is called.

since the UpdateProgress() method is used in percentage, i would put

Instance.progressBar.Step = Percent; 

into static Show() method

...
Instance.progressBar.Style = Style;
Instance.progressBar.Step = Percent; 
...

and you can see the it updating the progress bar precentage.

I'm using below example

TaskForm.Show(this, "Task is executing...", "Step 1 - Preparing...", 
                    "Runninig", true, ProgressBarStyle.Continuous);
for (int i = 1; i <= 100; i++)
{
  TaskForm.UpdateInstructionText("Step 1 - Executing..." + i );
  TaskForm.UpdateStatus("Running " + i);
  TaskForm.UpdateProgress(i);

  Thread.Sleep(1000);
}

Upvotes: 2

Related Questions