Сгенерированные тикером формы не отображаются правильно
Надеюсь, что это не так уж сложно следовать.
В настоящее время я работаю над небольшим приложением хронометража, которое работает в фоновом режиме. Каждый раз, когда тикер отключается, приложение предлагает пользователю сказать, что он делал с момента последнего запроса. В конце концов я сделаю так, чтобы приложение записало данные в электронную таблицу.
Один из имеющихся у меня вариантов позволяет пользователю выбрать, будет ли он / она использовать настройку приглашения по умолчанию (каждый раз, когда пропускается приглашение, оно остается видимым до тех пор, пока не будет создано следующее, то есть, если пользователь покинет его). В течение некоторого времени на его / ее компьютере может появиться довольно много приглашений, ожидающих заполнения), или он хотел бы объединить все приглашения (каждый раз, когда пропускается приглашение и появляется новое, старое закрыто, а новое охватывает время старого приглашения и нового приглашения).
Пользователь также может выбрать флажок, чтобы отключить подсказки. Когда он / она снова включает подсказки, появляется подсказка, в которой пользователю предлагается указать, что он делал, когда подсказки были выключены (полезно, когда пользователь запускает полноэкранные приложения и т. Д.).
Моя проблема в том, что когда я пытаюсь сгенерировать подсказки, они отображаются неправильно. Я не могу ими манипулировать, и ни один из элементов управления не отображается. Они в основном выглядят как пустые формы.
Вот мой код для генерации подсказок с помощью тикера:
public void ticker(object source, System.Timers.ElapsedEventArgs e)
{
if (groupMissed)
{
incrementsMissed += 1;
if (incrementsMissed > 1)
{
IncrementForm form = (IncrementForm)Application.OpenForms["IncrementForm"];
if (form.InvokeRequired)
{
form.Invoke(new MethodInvoker(delegate { form.Close(); }));
}
}
}
else
{
incrementsMissed = 1;
}
IncrementForm theIncrementForm = new IncrementForm(this, e.SignalTime);
theIncrementForm.Show();
latestIncrement = e.SignalTime;
}
А вот мой код для генерации подсказок с использованием флажка "выключить подсказки":
private void chkbxAlerts_Click(object sender, EventArgs e)
{
if (!chkbxAlerts.Checked)
{
// Ensures that the time missed is covered and restarts the timer
DateTime now;
now = DateTime.Now;
if ((now - latestIncrement).TotalMinutes >= 1) // Only records time if it is equal to or greater than one minute
{
// TO-DO: FIX
if (groupMissed)
{
incrementsMissed += 1;
if (incrementsMissed > 1)
{
IncrementForm form = (IncrementForm)Application.OpenForms["IncrementForm"];
if (form.InvokeRequired)
{
form.Invoke(new MethodInvoker(delegate { form.Close(); }));
}
}
}
else
{
incrementsMissed = 1;
}
IncrementForm theIncrementForm = new IncrementForm(this, now, latestIncrement);
theIncrementForm.Show();
latestIncrement = now;
}
timer.Enabled = true;
}
else
{
// Stops the timer
timer.Enabled = false;
}
}
Если вам нужны дальнейшие разъяснения, пожалуйста, дайте мне знать. Большое спасибо заранее за любую помощь, это беспокоит меня.
2 ответа
System.Timers.Timer
имеет свойство SynchronizingObject. Если вы установите это для главной формы (или формы, которая содержит таймер), то событие тика таймера будет вызвано в потоке GUI.
Обратите внимание, что System.Timers.Timer
имеет неприятную привычку глотать исключения, которые происходят в Elapsed
событие. Если ваш обработчик тиков выбрасывает исключение, вы его никогда не увидите. Это противная ошибка ловца. По этой причине я рекомендую использовать либо System.Windows.Forms.Timer
или же System.Threading.Timer
, Если вы используете таймер Windows Forms, в потоке GUI возникает событие elapsed. Если вы используете System.Threading.Timer
, вам придется использовать Invoke
как показывает Н.С.Гага в своем ответе.
См. " Глотание исключений - скрытие ошибок" для получения дополнительной информации о том, почему я не рекомендую использовать System.Timers.Timer
,
Я думаю, из того, что я вижу, не 100%, а ваш таймер порождает ваши окна в отдельном потоке (происходящем из вызова таймера таймера).
Хотя теоретически это может сработать (посмотрите на это Как открыть форму в потоке и заставить ее оставаться открытой)
... вам может быть намного лучше оставаться в главном потоке.
Попробуйте что-то вроде этого...
yourMainWindow.Invoke(new MethodInvoker(() =>
{
IncrementForm theIncrementForm = new IncrementForm(this, e.SignalTime);
theIncrementForm.Show();
latestIncrement = e.SignalTime;
}));
... это от вашего таймера - таким образом (как я вижу) вы должны иметь все это "в главном потоке" и сделать все намного проще для вас.
надеюсь это поможет