Странная ошибка Winforms? - PullRequest
       0

Странная ошибка Winforms?

1 голос
/ 17 сентября 2010

Я делаю приложение «Календарь» для себя и для обучения.

До сих пор у меня не было проблем с множественными формами, открытием новых друг над другом и т. Д.

Вот пример:

private void button1_Click(object sender, EventArgs e)
{
    if (ceForm != null) ceForm.Close();
    ceForm = new CalendarEventForm();
    ceForm.Show();
}

В любом случае, я теперь начал добавлять таймеры для всплывающей формы «напоминания» до того, как произойдут важные события в моем календаре (то есть за 1 час до и т. Д.).

Код устанавливает таймеры при загрузке программы, а затем по истечении каждого таймера это называется:

static void lazyTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    mainForm.ShowReminder((sender as LazyTimer).ReferredEvent);
}

LazyTimer точно такой же, как System.Timers.Таймер, за исключением добавленного свойства «ReferredEvent», которое ссылается на событие календаря, о котором нужно напомнить.

MainForm.ShowReminder () выглядит следующим образом:

public void ShowReminder(LazyEvent lazyEvent)
{
    ReminderForm newReminder = new ReminderForm();
    newReminder.LoadEvent(lazyEvent);
    newReminder.Show();
}

Странная вещьчто ReminderForm падает.Я пробовал это с другими формами (такими как CalendarEventForm, который, как я знаю, работает нормально), и они тоже вылетали.Однако, когда я пытаюсь загрузить ReminderForm нажатием кнопки на главной форме, она работает нормально.

Почему мои формы вылетают при загрузке (косвенно) по таймеру?

Ответы [ 3 ]

9 голосов
/ 17 сентября 2010

Краткий ответ: используйте System.Windows.Forms.Timer, а не System.Timers.Timer.

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

6 голосов
/ 17 сентября 2010

Если он упаковывает System.Timers.Timer, он будет запускаться в потоке пула потоков, что означает, что вы не можете выполнять там операции пользовательского интерфейса.

Вместо этого используйте System.Windows.Forms.Timer или установите SynchronizingObject в System.Timers.Timer для объекта пользовательского интерфейса, так что таймер сработает в потоке пользовательского интерфейса.

РЕДАКТИРОВАТЬ: другой момент ... лично я, вероятно, использовал бы лямбда-выражение илианонимный метод как обработчик события Tick таймера, который таким образом захватывает соответствующее событие и, таким образом, исключает дополнительный класс и дополнительный метод:

// Presumably we've got a local variable here, e.g. currentEvent
timer.Tick += delegate { mainForm.ShowReminder(currentEvent; };
0 голосов
/ 17 сентября 2010

Вы столкнулись с проблемой потоков.

Пожалуйста, используйте System.Windows.Forms.Timer при работе с System.Windows.Forms.

System.Timers.Timer не вызывает событие в цикле событий приложений, но напрямую вызывает обработчик событий, что приводит, в вашем случае, к операции перекрестного потока, которая не поддерживается Forms и вашим приложениемсбои.

Напротив, System.Windows.Forms.Timer будет легко вписываться в компонентную модель System.Windows.Forms.

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