Swanand
Swanand

Reputation: 4115

Form Not Responding when any other operation performed in C#

I have a form (Developed in C# using VS2010) with a Progress Bar. It's kind of stopwatch form where I fill the progress bar in say 10secs.... As Time elapses, Progress bar fills accordingly.... Means after 5secs, Progress Bar will be filled 50% and so on....

I used a for loop to perform this operation:-

for(int count=0;count<200;count++)
{
   progbar.performstep();
   progbar.update();
   update();
   Thread.Sleep(50);
}

I have used Thread.Sleep of 50msec so that progress bar updates smoothly. For 1sec, it increments in steps.

Problem is if I do anyother operation like Moving this form or even clicking on another icon on desktops makes this form "Not Responding".... But it perfoms the operation and at the end of 10 secs, It regains it's state and shows the pop up indicating 10secs are elapsed with Progress Bar Full.

Thanks for help and Sorry for using such complicated language.

Regards, Swanand

Update: I solved this problem with the help of Answers below.... One common mistake I got to know is forgetting "Applications.DoEvents()" along with "update()".... If you enter this line, there are less chances of getting "hanged"!

Upvotes: 10

Views: 36570

Answers (5)

Vishal Patwardhan
Vishal Patwardhan

Reputation: 317

If you want to run your code you should put this code in a function and call this function with one thread.

 public static void fun1()
        {
            for (int i = 0; i <= 10; i++)
            {
                Console.Write("This is function1");
                Console.Write("\n");

            }

        }
  Thread firstthread = new Thread(new ThreadStart(fun1));

  firstthread.Start();
  firstthread.suspend();//whenever you want your current control to stop.

b'caz Thread.sleep(100) will stop the whole context not that particular you want..

Upvotes: 1

Prashant
Prashant

Reputation: 966

Answer suggested by Marc will help. Lon running operations can make your application crash or not responsive. I have a blog post related to the usage of the background worker class.

http://midnightprogrammer.net/post/Using-Background-Worker-in-C.aspx

Upvotes: 0

Marc Gravell
Marc Gravell

Reputation: 1062492

You are blocking the UI thread, which means it isn't processing events such as "paint". To do this properly, you should be using something like BackgroundWorker, and just updating the UI from the progress event.

using System;
using System.Windows.Forms;
using System.ComponentModel;
using System.Threading;

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MyForm());
    }
}

class MyForm : Form
{
    Button btn;
    BackgroundWorker worker;
    ProgressBar bar;
    public MyForm()
    {
        Controls.Add(btn = new Button { Text = "Click me" });
        btn.Click += new EventHandler(btn_Click);

        Controls.Add(bar = new ProgressBar { Dock = DockStyle.Bottom, Visible = false, Minimum = 0, Maximum = 100 });

        worker = new BackgroundWorker { WorkerReportsProgress = true };
        worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
        worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
    }

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        bar.Visible = false;
        if (e.Error != null)
        {
            Text = e.Error.Message;
        }
        else if (e.Cancelled)
        {
            Text = "cancelled";
        }
        else
        {
            Text = e.Result == null ? "complete" : e.Result.ToString();
        }
        btn.Enabled = true;
    }

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        for (int count = 0; count < 100; count++)
        {
            worker.ReportProgress(count);
            Thread.Sleep(50);
        }
    }

    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        bar.Value = e.ProgressPercentage;
    }

    void btn_Click(object sender, EventArgs e)
    {
        bar.Value = 0;
        bar.Visible = true;
        btn.Enabled = false;
        worker.RunWorkerAsync();
    }
}

Upvotes: 11

Jon Skeet
Jon Skeet

Reputation: 1499760

You're performing a long-running operation on the UI thread, which means that the UI "message loop" (responsible for handling events such as user input and updating the screen) doesn't get a chance to run.

You should perform the long-running operation on a different thread (whether one you create yourself or a background thread) and either use BackgroundWorker to easily update your progress bar, or use Control.Invoke/BeginInvoke to marshall a delegate call back to the UI thread when you need to update the UI. (You mustn't update controls from the wrong thread.)

If your only UI interaction is filling in a progress bar, I suggest using BackgroundWorker.

If you're not really doing "real" work, just waiting for time to pass, you could use a System.Windows.Forms.Timer instead of all of this, however. That will "tick" on the UI thread, but won't block the UI thread between ticks. You should only use this if you don't have a lot of work to do though - if it really is just updating a progress bar, not (say) processing a file etc. Note that you shouldn't rely on the timer firing exactly "on time" - you should probably set the position of the progress bar based on the observed time, rather than the observed number of ticks.

Upvotes: 17

Anuraj
Anuraj

Reputation: 19598

You are blocking the Main UI thread. You can use a background worker to do this. You can find more details in MSDN

Upvotes: 2

Related Questions