2011-12-22 4 views
1

Я пытаюсь показать загрузку процессора и памяти в строке состояния формы MDI. Состояние CPU и памяти работают правильно, если я просто вызываю их методом. Но сейчас я хочу сделать таймер, который продолжает обновлять две метки до тех пор, как приложение работает:Таймер заставляет форму выйти сразу после запуска

public System.Threading.Timer MainTimer; 
public System.Threading.TimerCallback MainTimerCallback; 

private void InitializeTimer() 
{ 
    MainTimerCallback = new System.Threading.TimerCallback(MainTimer_Tick); 
    MainTimer = new System.Threading.Timer(MainTimerCallback,this,0,100); 
} 

private void MainTimer_Tick(object obj) 
{ 
    UpdateSystemDiagnostics(); 
} 

Тогда я закодировать это в моем MDI конструктор формы:

public MainForm() 
{ 
    InitializeComponent(); 

    InitializeSystemDiagnostics(); 
    InitializeTimer(); 
} 

Это для кода для моя диагностика:

private PerformanceCounter _cpuLoad; 
private PerformanceCounter _ramFree; 
public float[] SystemDiagnostic = new float[2] { 0, 0 }; 

private void InitializeSystemDiagnostics() 
{ 
    //Diagnostics 
    _cpuLoad = new PerformanceCounter { CategoryName = "Processor", CounterName = "% Processor Time", InstanceName = "_Total" }; 
    _ramFree = new PerformanceCounter("Memory", "Available MBytes"); 
} 

private void UpdateSystemDiagnostics() 
{ 
    SystemDiagnostic[0] = _cpuLoad.NextValue(); 
    SystemDiagnostic[1] = _ramFree.NextValue(); 

    _labelCpuStatus.Text = string.Format("CPU LOAD: ") + string.Format("{0:0.##}%", SystemDiagnostic[0]).PadRight(8); 
    _labelMemoryStatus.Text = string.Format("FREE MEMORY: {0}MB", SystemDiagnostic[1]); 
} 

Почему это вызывает закрытие формы, как только я ее открываю? Даже если я удалю отладку, он сразу открывается и закрывается!

Также мой другой вопрос: работает ли этот таймер на другом потоке? Если я передам много времени на событие Tick, будет ли он зависеть или заикаться?

UPDATE

Когда я поставил точку останова на этой линии:

_labelCpuStatus.Text = string.Format("CPU LOAD: ") + string.Format("{0:0.##}%", SystemDiagnostic[0]).PadRight(8); 

Я заметил, что он работает как 2 или 3 раза, и он обновляет метку, но она завершает работу без предупреждения или исключение!

+0

Как вы используете форму? то есть 'Program.cs' и' Main (...) '? –

+0

Как обычная winform ... да, она проходит через Program.cs –

ответ

3

Если форма просто открывается и закрывается немедленно, вероятно, у вас есть необработанное исключение внутри вашего кода конструктора. У WinForms есть раздражающая привычка глотать такие исключения. Если у вас вокруг Google, вы должны найти дополнительную информацию об этом. Вы можете просмотреть содержимое этого исключения (если я прав, подумав, что это причина), перейдя на Debug > Exceptions и установив флажок рядом с Исключения общего времени выполнения для языка под Thrown. Это должно нарушить все исключения по этой категории.

Что касается того, работает ли таймер на другом потоке или нет, лучший способ проверить - добавить Thread.Sleep(...some large number...) в обработчик для события Tick (когда ваша форма запущена) и посмотреть, закроет ли она форму. Если это так, он работает в одном потоке.

EDIT

Я только что быстрый взгляд на MSDN и это то, что я нашел о резьбе таймеров:

System.Windows.Forms.Timer:

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

System.Threading.Thread.Timer

Используйте TimerCallback делегат указать метод, который вы хотите таймер для выполнения. Делегат таймера указывается, когда таймер построен и не может быть изменен. Метод не выполняется в потоке, который создал таймер; он выполняется в потоке ThreadPool, поставляемом системой.

Так что если я прав в своем понимании; System.Windows.Forms.Timer выполняется в потоке пользовательского интерфейса (так что замораживает пользовательский интерфейс, если он выполняет длительные операции над ним), а System.Threading.Thread.Timer выполняет в другом потоке пользовательский интерфейс (так что не следует замораживать пользовательский интерфейс, если он выполняет длительные операции над ним).

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

+0

Ваш последний вопрос верен, но OP специально говорит об обновлении пользовательского интерфейса. Вы должны __want__ сделать это из потока пользовательского интерфейса. – Adam

+0

Да, да. Я просто пытался проиллюстрировать различия с таймерами. Тем не менее, вы можете выполнять длительные операции (не зависящие от каких-либо элементов пользовательского интерфейса) в отдельном потоке и переходить к потоку пользовательского интерфейса для обновления пользовательского интерфейса. –

+0

Невозможно обновить UI NOT из потока пользовательского интерфейса :) – Elastep

3

Использование System.Windows.Forms.Timer вместо System.Threading.Timer System.Threading.Timer запускает это событие в другом потоке. Но вы не можете изменить пользовательский интерфейс из другого потока, поскольку вы получите исключение операции перекрестного потока.

+0

Но я слышал, что один использует поток пользовательского интерфейса и заставляет пользовательский интерфейс быть невосприимчивым. Я ошибаюсь? –

+0

Нет другого способа изменения пользовательского интерфейса. Только из потока пользовательского интерфейса. Единственное, чего вы НЕ ДОЛЖНЫ НИКОГДА не делать, это долгие вычисления в нитке ui. Обновления текстовых меток - это нормально, и это то, что нужно сделать в потоке пользовательского интерфейса. – Elastep

+1

вот сравнение: http://msdn.microsoft.com/en-us/magazine/cc164015.aspx – Adam

1

если вы хотите, минимальные изменения, которые вы можете добавить это в свой код:

private void UpdateSystemDiagnostics() 
{ 
    SystemDiagnostic[0] = _cpuLoad.NextValue(); 
    SystemDiagnostic[1] = _ramFree.NextValue(); 
this.Invoke(new MethodInvoker(delegate 
      { 
       _labelCpuStatus.Text = string.Format("CPU LOAD: ") + string.Format("{0:0.##}%", SystemDiagnostic[0]).PadRight(8); 
    _labelMemoryStatus.Text = string.Format("FREE MEMORY: {0}MB", SystemDiagnostic[1]); 
      })); 

} 
+0

Спасибо, что добавил, насколько мне известно! –

Смежные вопросы