简体   繁体   中英

Accessing a Progress bar from (System.Timer)Timer Event gives "Cross-Thread Operation Not Valid)

I am designing a form in which I have to increase a Progress bar while an operation is being performed simultaneously (In other words, I am showing the progress of this operation). This operation takes 50 seconds. So I have used a System.Timer to Increase the Progress bar.

There isn't a single thread in my code. When I write Progress_bar.PerformStep() in Timer Event Handler, it gives error as "Cross Thread Operation Not Valid".

[From this error I analyzed that System.Timer must be creating a Thread and Runs the timer in it to perform multiple tasks.]

What should I do to increase my progress bar after every Second?

I tried solution given in this question. It removed the error but Now I can't see the progress bar increasing. Means it Starts.... No Increase for 50 sec and after it 100%.

Code is as follows:

Timer Declaration (It is Global):

public System.Timers.Timer Thetimer = new System.Timers.Timer(1000);

Event Declaration (This is in Constructor to make it...err...Public [May not be a correct word]):

Thetimer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);

Call:

 Thetimer.Start();

 blRetVal = FunctionToBeExecuted(parameter);

 Thetimer.Stop();

Event Handler:

 void _timer_Elapsed(object sender, ElapsedEventArgs e)
        {
           //StatusBar.PerformStep();  -- Tried This. It gives the Error

/* This doesn't give an error but Another issue Arises */

            if (InvokeRequired)
            {
                BeginInvoke(new Action(StatusBar.PerformStep));

            }
            else
                StatusBar.PerformStep();
        }

PS I am using C# and Visual Studio 2008

When you initialize the Timers.Timer object for use with a Windows Form, you must set the SynchronizingObject property of the timer instance to be the form.

systemTimersTimerInstance.SynchronizingObject = this; // this = form instance.

http://msdn.microsoft.com/en-us/magazine/cc164015.aspx

Rudy =8^D

It sounds like you're performing your "background" operation on the main thread, which is why your progress bar doesn't update when you invoke it.

Have a look at BackgroundWorker .

OK. Jon B is right. You'll have to have the long running task in a thread, there is no way around that. Simplified, you're doing this:

public partial class Form1 : Form
{
    // ...

    public System.Timers.Timer timer = new System.Timers.Timer(1000); 

    private void Form1_Load(object sender, EventArgs e)
    {
        timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_elapsed);

        timer.Start();

        // Simulates your long running task (FunctionToBeExecuted)
        // NOTE: This freezes the main UI thread for 10 seconds, 
        //       so nothing will be drawn *at all*            
        Thread.Sleep(10000); 

        timer.Stop(); 

    }

    void timer_elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        if (InvokeRequired) 
            this.BeginInvoke(new Action(progressBar1.PerformStep));            
        else
            progressBar1.PerformStep(); 
    }        
}

As you can see in the Load event, you're not only halting the progress bar, you're halting the main UI thread. That's just not acceptable to most users and all good developers should have another option in their toolset.

The only way around this (except running another process) is running the task in a different thread. One of the easiest ways is using a BackgroundWorker, it's really easy. Here are the changes you need:

public partial class Form1 : Form
{            
    // ...

    private void Form1_Load(object sender, EventArgs e)
    {                                              
        BackgroundWorker worker = new BackgroundWorker();
        worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        worker.RunWorkerCompleted += 
          new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
        worker.RunWorkerAsync();

    }

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        // Your work is completed, not needed but can be handy
        // e.g. to report in some way that the work is done:
        progressBar1.Value = progressBar1.Maximum;
    }

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_elapsed);
        timer.Start();

        // Simulates your long running task (FunctionToBeExecuted)
        // Your main UI thread is free!
        Thread.Sleep(10000);

        timer.Stop();
    }

    // ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM