C# Ticker生成的表单显示不正确

C# Ticker生成的表单显示不正确,c#,forms,prompt,ticker,C#,Forms,Prompt,Ticker,希望这不是很难做到 我目前正在开发一个在后台安静运行的小型timelogging应用程序。每次股票代码关闭时,应用程序都会提示用户说出自上次提示后他/她在做什么。我最终会让应用程序将数据写入电子表格 到目前为止,我提供的其中一个选项允许用户选择是否使用默认提示设置(每次错过提示时,它将一直可见,直到创建下一个提示,这意味着如果用户离开计算机一段时间,屏幕上可能会有相当多的提示等待填写)或者希望合并所有提示(每次错过提示并弹出新提示时,旧提示关闭,新提示覆盖旧提示和新提示的时间) 用户还可以选择一

希望这不是很难做到

我目前正在开发一个在后台安静运行的小型timelogging应用程序。每次股票代码关闭时,应用程序都会提示用户说出自上次提示后他/她在做什么。我最终会让应用程序将数据写入电子表格

到目前为止,我提供的其中一个选项允许用户选择是否使用默认提示设置(每次错过提示时,它将一直可见,直到创建下一个提示,这意味着如果用户离开计算机一段时间,屏幕上可能会有相当多的提示等待填写)或者希望合并所有提示(每次错过提示并弹出新提示时,旧提示关闭,新提示覆盖旧提示和新提示的时间)

用户还可以选择一个勾选框来关闭提示。当他/她再次打开提示时,会弹出一个提示,要求用户填写关闭提示时他/她正在做的事情(在用户运行全屏应用程序等时很有用)

我的问题是,当我尝试生成提示时,它们无法正确显示。我根本无法操纵它们,并且没有任何控件显示。它们基本上看起来像空表单

以下是我使用ticker生成提示的代码:

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

如果您需要任何进一步的澄清,请让我知道。提前非常感谢您的帮助,这一直困扰着我。

我认为,从我所看到的,不是100%,而是您的计时器正在一个单独的线程中生成您的窗口(来自计时器计时器调用)

从理论上讲,这是可行的(看看这个)
…你最好呆在主线内

试试这样的

yourMainWindow.Invoke(new MethodInvoker(() =>
    {
        IncrementForm theIncrementForm = new IncrementForm(this, e.SignalTime);
        theIncrementForm.Show();
        latestIncrement = e.SignalTime;
    }));
…这是从你的计时器-这样(正如我所看到的)你应该把它都“放在主线程上”,让事情变得更容易


希望这有帮助

我想,从我所看到的,不是100%,而是你的计时器正在一个单独的线程中生成你的窗口(来自计时器代码调用)

从理论上讲,这是可行的(看看这个)
…你最好呆在主线内

试试这样的

yourMainWindow.Invoke(new MethodInvoker(() =>
    {
        IncrementForm theIncrementForm = new IncrementForm(this, e.SignalTime);
        theIncrementForm.Show();
        latestIncrement = e.SignalTime;
    }));
…这是从你的计时器-这样(正如我所看到的)你应该把它都“放在主线程上”,让事情变得更容易


希望这有助于

系统。计时器。计时器
有一个属性。如果将其设置为主窗体(或包含计时器的窗体),则会在GUI线程上引发计时器勾号事件

请注意,
System.Timers.Timer
有一个讨厌的习惯,即吞咽
已用事件中发生的异常。如果您的tick处理程序抛出异常,您将永远看不到它。这是一个讨厌的臭虫藏身处。因此,我建议使用
System.Windows.Forms.Timer
System.Threading.Timer
。如果使用Windows窗体计时器,将在GUI线程上引发已用事件。如果使用
System.Threading.Timer
,则必须使用
Invoke
,正如NSGaga在回答中所示


有关我为什么不鼓励使用
System.Timers.Timer

System.Timers.Timer
的更多信息,请参阅。如果将其设置为主窗体(或包含计时器的窗体),则会在GUI线程上引发计时器勾号事件

请注意,
System.Timers.Timer
有一个讨厌的习惯,即吞咽
已用事件中发生的异常。如果您的tick处理程序抛出异常,您将永远看不到它。这是一个讨厌的臭虫藏身处。因此,我建议使用
System.Windows.Forms.Timer
System.Threading.Timer
。如果使用Windows窗体计时器,将在GUI线程上引发已用事件。如果使用
System.Threading.Timer
,则必须使用
Invoke
,正如NSGaga在回答中所示


有关我为什么不鼓励使用
System.Timers.Timer

的更多信息,请参阅。这是一个结构非常完善的问题,但仍然缺少一些东西。你的股票是计时器驱动的吗?计时器正在从另一个线程调用-您无法从中更新GUI表单(尽管您可以在不同的线程中显示/生成表单-不确定在您的情况下可能会“给出”什么)…是的,这是另一个线程确定是的,计时器上的已用事件调用了计时器。我怎样才能避开你提到的这个GUI问题?你能设计一个小的“可运行”示例吗?还有更多的事我很抱歉guessing@NSGaga我只是做了一点快速的研究,并意识到问题确实是因为我试图在计时器线程中执行UI功能,就像你说的那样。我只需要弄清楚如何通过UI线程执行上述函数。这是一个令人困惑的问题。你有一个一直运行的主窗口吗?这是一个很好的问题——尽管仍然缺少一些东西。你的股票是计时器驱动的吗?计时器正在从另一个线程调用-您无法从中更新GUI表单(尽管您可以在不同的线程中显示/生成表单-不确定在您的情况下可能会“给出”什么)…是的,这是另一个线程确定是的,计时器上的已用事件调用了计时器。我怎样才能避开你提到的这个GUI问题?你能设计一个小的“可运行”示例吗?还有更多的事我很抱歉guessing@NSGaga我只是做了一点快速的研究,并意识到问题确实是因为我试图在计时器线程中执行UI功能,就像你说的那样。我只需要弄清楚如何通过UI线程执行上述函数。这是令人困惑的东西。你有一个主窗口一直在运行吗?你的解决方案工作得很好,谢谢!只有一件事。系统