Click here to Skip to main content
15,897,291 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
when I use Timer to performstep a progressbar in a form,I find only after the consuming time function ends,the progress bar can perform step.I don't know why.Help me.
Below is my code.
C#
public partial class Form1 : Form
    {
        System.Timers.Timer aTimer;
        public Form1()
        {
            InitializeComponent();
            aTimer = new System.Timers.Timer();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            aTimer = new System.Timers.Timer(2000);
            aTimer.Elapsed += new System.Timers.ElapsedEventHandler(aTimer_Elapsed);
            aTimer.Enabled = true;
            int n = Convert.ToInt32(textBox1.Text);
            long m = ComputeFibonacci(n);
            Console.WriteLine("Fibonacci:" + m);
            aTimer.Enabled = false;
        }
         void aTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
            if (InvokeRequired)
            {
                this.Invoke(new Action(progressBar1.PerformStep));
                Application.DoEvents();
            }
            else
            {
                progressBar1.PerformStep();
                Application.DoEvents();
            }
            Console.WriteLine(progressBar1.Value);
        }
        /// <summary>
         /// Compute  Fibonacci
        /// </summary>
        /// <param name="n"></param>
        /// <returns></returns>
        long ComputeFibonacci(int n)
        {
            // The parameter n must be >= 0 and <= 91.
            // Fib(n), with n > 91, overflows a long.
            if ((n < 0) || (n > 91))
            {
                throw new ArgumentException(
                    "value must be >= 0 and <= 91", "n");
            }
            long result = 0;
            // Abort the operation if the user has canceled.
            // Note that a call to CancelAsync may have set 
            // CancellationPending to true just after the
            // last invocation of this method exits, so this 
            // code will not have the opportunity to set the 
            // DoWorkEventArgs.Cancel flag to true. This means
            // that RunWorkerCompletedEventArgs.Cancelled will
            // not be set to true in your RunWorkerCompleted
            // event handler. This is a race condition.
            if (n < 2)
            {
                result = 1;
            }
            else
            {
                result = ComputeFibonacci(n - 1) +
                         ComputeFibonacci(n - 2);
            }

            return result;
        }
Posted

You'll have to start a separate thread to do the calculation because you're calling the fibonacci computing method from within an event handler all other GUI events will not be processed until the handler of the button click event has returned. In your case this will not happen until the computation of the fibonacci number has finished.

Regards,
— Manfred
 
Share this answer
 
Comments
aGISer 4-Jul-13 23:52pm    
Thank you.I have to use the interface in ArcGIS Engine.But there are many methods that don't support multi-thread.How can I do?
I could work, but makes little to no sense, but the following reason: you need to show the progress in your Fibonacci calculation, but you simply show then number of timer events. You are going to show nothing useful, isn't it obvious?

The solution is quite obvious: perform Fibonacci calculation in a separate thread. In this way, you always know at what iteration you are, so you can notify the progress bar accordingly. As Fibonacci algorithm is linear (Fibonacci sequence is itself defined in terms of algorithm), the number of iteration will also be proportional to time, that is, this is O(N) time complexity.

Of course, as all UI operations, including progress bar update, should be done in your application's UI thread, also do it using System.Windows.Forms.Control.Invoke. Only you don't need to check InvokeRequired — it is always required in this scenario. And main thing here it: don't call Application.DoEvents. Just don't.

Please see:
http://en.wikipedia.org/wiki/Big_O_notation[^],
http://en.wikipedia.org/wiki/Time_complexity[^],
http://en.wikipedia.org/wiki/Computational_complexity_theory[^],
http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx[^],
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired.aspx[^].

That's it.

Note that using a timer is generally a bad idea even when it is applicable. A thread is very typically better, as it's easy to represent some linear behavior. Also, timers inherently present problems with reliability. For example, did you ever tried to address the problem when a new timer event is invoked when the execution of a handler called by a previous event is still incomplete? The thread approach does not present such problems.

One little advice: from the very beginning, get rid of auto-generated names like "Form1", "Button1_Click", "progressBar1", etc. Not only they are ugly and irritating, they are not readable, does not give you the idea on what they do, semantically, and they even violate (good) Microsoft naming conventions: no numerals, no underscore. Rename all names using the refactoring engine of Visual Studio. Never use auto-generated names, use semantically sensible names.

—SA
 
Share this answer
 
Comments
aGISer 4-Jul-13 23:49pm    
Thank you.
Sergey Alexandrovich Kryukov 5-Jul-13 0:17am    
You are very welcome.
Good luck, call again.
—SA
aGISer 4-Jul-13 23:50pm    
I'd like to use backgroundworker.
Sergey Alexandrovich Kryukov 5-Jul-13 0:17am    
You can...
—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900