Доступ к индикатору хода выполнения из (System.Timer) события таймера дает «операция с несколькими потоками не действительна» - PullRequest
0 голосов
/ 27 октября 2010

Я разрабатываю форму, в которой мне нужно увеличить индикатор выполнения, когда операция выполняется одновременно (другими словами, я показываю ход этой операции).Эта операция занимает 50 секунд.Поэтому я использовал System.Timer, чтобы увеличить индикатор прогресса.

В моем коде нет ни одной темы.Когда я пишу Progress_bar.PerformStep() в обработчике событий таймера, он выдает ошибку «Операция с перекрестными потоками недействительна».

[Из этой ошибки я проанализировал, что System.Timer должен создавать поток и запускает в нем таймер для выполнения нескольких задач.]

Что я должен делать, чтобы увеличивать индикатор выполнения после каждогоВторой?

Я пробовал решение, данное в этом вопросе.Ошибка устранена, но теперь я не вижу увеличения индикатора выполнения.Означает, что начинается .... Нет увеличения в течение 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();
        }

PS Я использую C # и Visual Studio 2008

Ответы [ 3 ]

4 голосов
/ 01 ноября 2010

Когда вы инициализируете объект Timers.Timer для использования с формой Windows, необходимо задать для свойства SynchronizingObject экземпляра таймера следующую форму:

systemTimersTimerInstance.SynchronizingObject = this;// this = экземпляр формы.

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

Rudy = 8 ^ D

3 голосов
/ 27 октября 2010

OK. Джон Б. прав. Вы должны будете иметь долгосрочную задачу в потоке, нет никакого способа обойти это. Упрощенно, вы делаете это:

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, вы не только останавливаете индикатор выполнения, но и основной поток пользовательского интерфейса. Это просто не приемлемо для большинства пользователей, и у всех хороших разработчиков должен быть другой вариант в их наборе инструментов.

Способ only (кроме запуска другого процесса) - запуск задачи в другом потоке. Одним из самых простых способов является использование 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();
    }

    // ...
}
3 голосов
/ 27 октября 2010

Похоже, вы выполняете «фоновую» операцию в главном потоке, поэтому ваш индикатор выполнения не обновляется, когда вы вызываете его.

Посмотрите на BackgroundWorker .

...