1

I made a form that plays a progressbar role here's the code i made

  public partial class PXProgressBar : Form
    {
        public delegate bool CancelEvent();
        public event CancelEvent cancel_e;

        public Boolean ProcessCancelled
        {
            get;
            set;
        }
        public PXProgressBar(bool EnableCancel) 
        {
            InitializeComponent();
            ProcessCancelled = false;
            progressBar1.Minimum = 0;
            if (!EnableCancel)
                Cancelbtn.Visible = false;

        }
        public  void increament(int step)
        {
            if (progressBar1.Value < progressBar1.Maximum-1)
            {
                progressBar1.Value++;
                progressBar1.Caption = progressBar1.Value.ToString() + " of " + progressBar1.Maximum;
                progressBar1.Refresh();

            }

            else
            {
                progressBar1.Value++;
                progressBar1.Caption = progressBar1.Value.ToString() + " of " + progressBar1.Maximum;
                if (this.TopMost)
                    this.TopMost = false;
                this.Update();
                this.Hide();
                this.WindowState = FormWindowState.Minimized;
               // this.Dispose();
            }

        }
        public void SetMaximum(int MaximumValue)
        {
            if (MaximumValue <= 0)
            {
                progressBar1.Maximum = 0;
                return;
            }
            if (progressBar1.Minimum != 0 && MaximumValue < progressBar1.Minimum)
            {
                progressBar1.Maximum = progressBar1.Minimum;
                return;
            }
            progressBar1.Maximum = MaximumValue;


        }
        public void SetMinimum(int MinimumValue)
        {
            progressBar1.Value = 0;
            if (MinimumValue <= 0)
            {

                progressBar1.Minimum = 0;
                return;
            }
            if (progressBar1.Maximum != 100 && MinimumValue > progressBar1.Maximum)
            {
                progressBar1.Minimum = progressBar1.Maximum;
                return;
            }
            progressBar1.Minimum= MinimumValue;
        }
        public void SetTitle(string ProcessTitle)
        {
            this.ProgressTitlelb.Text =ProcessTitle;// ProcessTitle;
            //this.ProgressTitlelb.Left = (this.panel1.Width - this.ProgressTitlelb.Width) / 2;
            //this.ProgressTitlelb.Top = (this.panel1.Height - this.ProgressTitlelb.Height) / 2;
            this.Update();
        }

        private void Cancelbtn_Click(object sender, EventArgs e)
        {

            ProcessCancelled = true;
            bool disposeRequired =cancel_e();
            if(disposeRequired)
             this.Dispose();
        }

        private void PXProgressBar_Shown(object sender, EventArgs e)
        {
            this.Update();
        }

    }

and i call the form through this code

  if (ProgressBar == null)
   ProgressBar = new PXProgressBar(true);
   ProgressBar.SetTitle("Saving ...");
   ProgressBar.SetMinimum(0);
   ProgressBar.SetMaximum(100);
   ProgressBar.TopMost = true;
   ProgressBar.Show();
   Application.DoEvents();

regarding that the past few lines are in a unction that is called throught a thread but when i run it the form hangs so i cant set a Cancel Button in the form to let the user cancel the operation

Sara S.
  • 1,365
  • 1
  • 15
  • 33
  • 1
    You cannot get a form to keep itself updated without a message loop. Use BackgroundWorker. – Hans Passant Sep 13 '11 at 13:05
  • I don't think we can really pinpoint the problem unless you can provide a demo that shows the problem. Can you put together a small app with this class to show the problem? – Skizz Sep 14 '11 at 12:28

5 Answers5

2

Your code looks like it should be fine so I can only assume that you are doing a long running operation on the UI thread which would cause the UI to look like its hung. You need to perform long running operations on a background thread so that the UI thread remains responsive enough to respond to button clicks etc. There are many many articles about this if you consult your friend Google.

More info on that here http://www.idevforfun.com/index.php/2010/01/10/windows-ui-threading/

I agree with Skizz on the DoEvents call ... there's only a very few rare cases where that call is needed and mostly its in the framework itself that it gets used.

iDevForFun
  • 978
  • 6
  • 10
1

The problem might be the DoEvents method call. From this MSDN page:

Calling this method causes the current thread to be suspended while all waiting window messages are processed. If a message causes an event to be triggered, then other areas of your application code may execute. This can cause your application to exhibit unexpected behaviors that are difficult to debug. If you perform operations or computations that take a long time, it is often preferable to perform those operations on a new thread. For more information about asynchronous programming, see Asynchronous Programming Overview.

I don't think the DoEvents call is necessary. If you need to halt the code after the Show for the operation to complete, then use a System.Threading.EventWaitHandle instead.

Skizz
  • 69,698
  • 10
  • 71
  • 108
  • When i remove DoEvents the labels in my progressbar form looks black block and can't see the title of the form – Sara S. Sep 14 '11 at 07:15
  • @Sara: It seems that your form is not receiving paint events. Don't forget that all form code needs to be in the same thread as the main form, it won't work in a different thread. – Skizz Sep 14 '11 at 07:20
  • Yes it seems that , because the progressbar is not updated unless i call progressbar.Update(); but i still can't figure out why the paint is not called from the same thread,Thank you] – Sara S. Sep 14 '11 at 08:29
  • I aslo call the increament function through a for loop ,so i wonder if the speed will affect it,also i made a cencel button in the progressbar form , bubt the cursor is converting to a waitinghourglass when i enter the progressbar form – Sara S. Sep 14 '11 at 08:35
  • Skizz, I made a breakpoint in the Paint event of the progressbar form and it does not enter in it , is that normal?? – Sara S. Sep 14 '11 at 08:46
  • @Sara: No. I've added another answer detailing how this should be implemented. Hope that helps. – Skizz Sep 14 '11 at 08:58
1

There's some link maybe helpful for you about progressbar:

How do I implement a progress bar in C#?

Hope this help.

Community
  • 1
  • 1
Thinhbk
  • 2,194
  • 1
  • 23
  • 34
1

You need to make sure the GUI elements are created on the main form thread and not from a separate thread. So, you need to get you thread that is doing the work to get the main form thread to display and update the progress bar. This is going to take a bit of refactoring.

So, in your worker thread:

void DoWork () // of whatever it's called
{
  main_form.CreateProgressBar ();
  while (doing stuff)
  {
    main_form.IncrementProgressBar ();
    do stuff
  }
  main_form.DestroyProgressBar ();
}

And in the main form:

delegate void Callback ();

void CreateProgressBar ()
{
   if (InvokeRequired)
   {
     Invoke (new Callback (CreateProgressBar));
   }
   else
   {
     progress_bar = CreateProgressBar ();
   }
 }

void IncrementProgressBar ()
{
   if (InvokeRequired)
   {
     Invoke (new Callback (IncrementProgressBar ));
   }
   else
   {
     progress_bar.IncrementProgressBar ();
   }
 }

void DestroyProgressBar ()
{
   if (InvokeRequired)
   {
     Invoke (new Callback (DestroyProgressBar));
   }
   else
   {
     progress_bar.Close ();
     progress_bar = null;
   }
 }

The InvokeRequired determines if the calling thread is the same as the GUI thread. If the calling thread is not the GUI thread, the Invoke is used to changed thread context. This is the synchronous version and won't complete until the invoked method is finished. There is an asynchronous version called BeginInvoke but this isn't really needed for what your doing.

Skizz
  • 69,698
  • 10
  • 71
  • 108
  • I used this code but with MethodInvoker but when i place a breakpoint on InvokeRequired i get it with false , i also noticed that when i replaced ProgressBar.Show with ProgressBar.ShowDialog the label placed in the form appears. sure i can't use it because i want to access it to increament it. – Sara S. Sep 14 '11 at 09:57
  • Skizz, the problem has been solved when i placed Application.DoEvents(); in the caller for loop , do you think it's a good solution?? – Sara S. Sep 14 '11 at 13:42
  • 1
    @Sara: Ah, I see. The DoWork function needs to be in its own thread: I think `Thread t = new Thread (new ThreadProc (DoWork)); t.Start ();` will do it. That would also explain why InvokeRequired returned false, you're doing all your work in the GUI thread so it was stopping the form from updating correctly. That's also why DoEvents appears to work. You are manually suspending your work to let the form process events. It's not a good solution. Using a thread will give a speed benefit as it can utilise multiple core CPUs better. – Skizz Sep 14 '11 at 13:49
  • @ Skizz, i found ittttttttt , the problem was in calling progressbarform.show() in a thread so when i show it in the main thread it works fine, Really Thanks for your help – Sara S. Sep 15 '11 at 09:56
0

Just create other thread for progressbar and use it in background

Motorcode
  • 101
  • 3
  • that appears to be a blanket statement. It could be useful as a comment. Answers are appreciated better if there is a small demonstration/steps of how to tie it together in the context of the question. – sehe Sep 13 '11 at 17:24
  • Thanks for this message, i'll know about it – Motorcode Sep 13 '11 at 18:46