Таймер заставляет форму выходить сразу после запуска - PullRequest
1 голос
/ 22 декабря 2011

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

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 раза и обновляет метку, но выходит без предупреждения или исключения!

Ответы [ 3 ]

3 голосов
/ 22 декабря 2011

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

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

РЕДАКТИРОВАТЬ

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

System.Windows.Forms.Timer:

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

System.Threading.Thread.Timer

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

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

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

3 голосов
/ 22 декабря 2011

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

1 голос
/ 22 декабря 2011

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

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

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...