从(System.Timer)定时器事件访问进度条使“跨线程操作无效”

时间:2010-10-27 13:38:12

标签: c# timer progress-bar multithreading

我正在设计一个表单,我必须在同时执行操作时增加进度条(换句话说,我正在显示此操作的进度)。   此操作需要50秒。所以我使用System.Timer来增加进度条。

我的代码中没有单个线程。当我在Timer事件处理程序中编写Progress_bar.PerformStep()时,它会将错误称为“交叉线程操作无效”。

[从这个错误中我分析了System.Timer必须创建一个Thread并在其中运行计时器以执行多个任务。]

我应该怎样做才能在每秒后增加进度条?

我尝试了在this问题中给出的解决方案。它删除了错误,但现在我看不到进度条增加。意味着它开始......没有增加50秒,然后是100%。

代码如下:

计时器声明(全局):

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

事件声明(这是在构造函数中使它...错误...公开[可能不是一个正确的词]):

Thetimer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);

呼叫:

 Thetimer.Start();

 blRetVal = FunctionToBeExecuted(parameter);

 Thetimer.Stop();

事件处理程序:

 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();
        }

P.S。我正在使用C#和Visual Studio 2008

3 个答案:

答案 0 :(得分:4)

初始化Timers.Timer对象以与Windows窗体一起使用时,必须将timer实例的SynchronizingObject属性设置为窗体。

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

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

Rudy = 8 ^ D

答案 1 :(得分:3)

听起来你正在主线程上执行“后台”操作,这就是你调用它时进度条没有更新的原因。

查看BackgroundWorker

答案 2 :(得分:3)

行。 Jon B是对的。你必须在一个线程中拥有长时间运行的任务,没有办法解决这个问题。简化,你这样做:

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(); 
    }        
}

正如您在Load事件中看到的那样,您不仅要暂停进度条,还要暂停主UI线程。这对大多数用户来说是不可接受的,所有优秀的开发人员都应该在他们的工具集中有另一种选择。

围绕此方式的 方式(运行另一个进程除外)正在另一个线程中运行该任务。最简单的方法之一是使用BackgroundWorker,它非常简单。以下是您需要的更改:

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();
    }

    // ...
}
相关问题