2013-03-15 2 views
1

поэтому, когда я пытаюсь нажать «кнопка 2», я ожидаю, что произойдут две вещи: а) «dowsomething» - это сделать свою вещь в классе «сейчас». б) Пока он что-то делает, я хочу, чтобы он подсчитал, сколько времени это займет. Однако, поскольку «dosomething» является программой голодной, Form1 зависает, и он не запускает таймер. Я немного новичок в C#, поэтому я не знаю, как запустить его в фоновом режиме. Так что любые идеи вне коробки? Благодарю.C# Таймер не спустится, чтобы сформировать замораживание

 int time = 0; 
    private void button2_Click(object sender, EventArgs e) 
    { 
      timer1.Start(); 
      nowthen now = new nowthen(); 
      now.dosomething(withthis); //This task is program hungry and causes the form to freeze 
      timer1.Stop(); 
      time = 0; 
    } 
    private void timer1_Tick(object sender, EventArgs e) 
    { 
     time = time + 1; 
     label2.Text = time.ToString(); 
     label2.Refresh(); 
    } 
+3

Рекомендуемое чтение: [Фоновые рабочие темы] (http://www.albahari.com/threading/part3.aspx # _BackgroundWorker) –

+0

Вы делаете это неправильно в целом. Пойдите, прочитайте о очереди сообщений Windows, а затем выполните много времени в другом потоке, чтобы пользовательский интерфейс мог оставаться отзывчивым. –

ответ

2

Для .NET 4 использования:

Task.Factory.StartNew((Action) delegate() 
{ 
    // this code is now executing on a new thread. 
    nowthen now = new nowthen(); 
    now.dosomething(withthis); 

    // to update the UI from here, you must use Invoke to make the call on UI thread 
    textBox1.Invoke((Action) delegate() 
    { 
      textBox1.Text = "This update occurs on the UI thread"; 
    }); 
}); 
+0

Почему не просто '() =>' вместо '(Action) delegate()'? –

+0

личное предпочтение – paul

+0

Это выглядит хорошо, однако в задании указано, что «Задача не существует в текущем контексте». Я использую .NET 4. – Marshal

2

Если вы просто хотите, чтобы время, как долго что-то берет, используйте System.Diagnostics.Stopwatch.

Stopwatch sw = Stopwatch.StartNew(); 
nowThen = new nowThen(); 
no.dosomething(withthis); 
sw.Stop(); 
// you can get the time it took from sw.Elapsed 

Это не будет обновлять этикетку с истекшим временем.

+1

Не будет отсчитывать таймер таким образом. – paul

3

В Windows Forms весь ваш пользовательский интерфейс работает на одном потоке. Это включает таймер - таймер выполняется за кулисами с сообщениями Windows.

Ваш вопрос на самом деле два вопроса: -

  1. Как раз операция в C#/Windows Forms?

Как быстро что-то зависит от точности, которую вы ищете. Для точности в области +/- 10 мс вы можете использовать Environment.TickCount - сохранить его значение перед вашей работой, затем получить значение снова после и вычесть сохраненное значение - и у вас есть продолжительность.

Точнее является Секундомер класс System.Threading - см http://www.dotnetperls.com/stopwatch

  1. Как я могу запустить задачу «в фоновом режиме»?

Чтобы выполнить операцию в фоновом режиме, вам нужно запустить ее в другом потоке. Самый простой, спроектированный дружелюбный (но, возможно, не такой гибкий способ) - использовать компонент BackgroundWorker. Это обертывание с использованием рабочего потока для выполнения операции для вас. См. http://www.dotnetperls.com/backgroundworker за хорошее объяснение того, как это сделать.

Более продвинутый и более гибкий, чтобы создать свой собственный поток для выполнения работы. Тем не менее, это создаст некоторые важные проблемы для рассмотрения того, как синхронизировать происходящее - как только вы начнете свой поток, ваш вызов метода завершается (он асинхронный), и вам нужно иметь механизм для уведомления вашего кода пользовательского интерфейса, который законченный. Этот пример кажется таким же хорошим, как любой из того, как создать свой собственный поток: http://www.daveoncsharp.com/2009/09/create-a-worker-thread-for-your-windows-form-in-csharp/

1

Я думаю, я тоже это сделаю, хотя это не так элегантно, как решение @ paul.

timer1.Start(); 
var bw = new BackgroundWorker(); 
bw.DoWork += (s, e) => { now.dosomething((myArgumentType)e.Argument); }; 
bw.RunWorkerCompleted += (s, e) => { timer1.Stop(); }; 
bw.RunWorkerAsync(withthis); 

Это запускает таймер, создает новый BackgroundWorker поток, говорит он, что работать в методе DoWork (DoSomething работает в отдельном потоке), а затем останавливает таймер в методе RunWorkerCompleted (после того, как DoSomething закончена, управление возвращается к основному потоку в RunWorkerCompleted).