Сгенерированные тикером формы не отображаются правильно

Надеюсь, что это не так уж сложно следовать.

В настоящее время я работаю над небольшим приложением хронометража, которое работает в фоновом режиме. Каждый раз, когда тикер отключается, приложение предлагает пользователю сказать, что он делал с момента последнего запроса. В конце концов я сделаю так, чтобы приложение записало данные в электронную таблицу.

Один из имеющихся у меня вариантов позволяет пользователю выбрать, будет ли он / она использовать настройку приглашения по умолчанию (каждый раз, когда пропускается приглашение, оно остается видимым до тех пор, пока не будет создано следующее, то есть, если пользователь покинет его). В течение некоторого времени на его / ее компьютере может появиться довольно много приглашений, ожидающих заполнения), или он хотел бы объединить все приглашения (каждый раз, когда пропускается приглашение и появляется новое, старое закрыто, а новое охватывает время старого приглашения и нового приглашения).

Пользователь также может выбрать флажок, чтобы отключить подсказки. Когда он / она снова включает подсказки, появляется подсказка, в которой пользователю предлагается указать, что он делал, когда подсказки были выключены (полезно, когда пользователь запускает полноэкранные приложения и т. Д.).

Моя проблема в том, что когда я пытаюсь сгенерировать подсказки, они отображаются неправильно. Я не могу ими манипулировать, и ни один из элементов управления не отображается. Они в основном выглядят как пустые формы.

Вот мой код для генерации подсказок с помощью тикера:

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

... это от вашего таймера - таким образом (как я вижу) вы должны иметь все это "в главном потоке" и сделать все намного проще для вас.

надеюсь это поможет

Другие вопросы по тегам