希望这并不难理解。
我目前正在开发一个在后台安静运行的小型时间日志应用程序。每次自动收报机运行时,应用程序会提示用户说出自上次提示以来他/她正在做什么。我最终会让应用程序将数据写入电子表格。
我到目前为止的一个选项使用户可以选择是否要使用默认提示设置(每次错过提示时,它都会保持可见,直到创建下一个提示,这意味着用户离开他/她的电脑一段时间,屏幕上可能会有相当多的提示等待填写)或者想要将所有提示组合起来(每次错过提示并弹出一个新提示时,旧的一个关闭,新的一个覆盖旧提示和新提示的时间。)
用户还可以选择一个复选框以关闭提示。当他/她再次打开提示时,会弹出一个提示,要求用户在提示关闭时填写他/她正在做的事情(当用户运行全屏应用程序时很有用等)。
我的问题是,当我尝试生成提示时,它们无法正确显示。我根本无法操纵它们,也没有显示任何控件。它们基本上看起来像空的形式。
这是我使用代码生成提示的代码:
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;
}
}
如果您需要进一步说明,请告知我们。非常感谢您提供任何帮助,这一直困扰着我。
答案 0 :(得分:2)
我认为,从我所看到的,不是100%,但你的计时器是在一个单独的线程中产生你的窗口(来自计时器自动收报机)。
虽然理论上可以起作用(看看这个How to open a form in a thread and force it to stay open)
...你可能会更好地留在主线程中。
尝试这样的事情......
yourMainWindow.Invoke(new MethodInvoker(() =>
{
IncrementForm theIncrementForm = new IncrementForm(this, e.SignalTime);
theIncrementForm.Show();
latestIncrement = e.SignalTime;
}));
......这是来自你的计时器 - 这样(我可以看到)你应该把它全部放在主线程上,让事情变得更容易。
希望这会有所帮助
答案 1 :(得分:2)
System.Timers.Timer
具有SynchronizingObject属性。如果将其设置为主窗体(或包含计时器的窗体),则会在GUI线程上引发计时器标记事件。
请注意System.Timers.Timer
有吞咽Elapsed
事件中发生的异常的恶习。如果您的tick处理程序抛出异常,您将永远不会看到它。这是一个讨厌的虫子。因此,我建议您使用System.Windows.Forms.Timer
或System.Threading.Timer
。如果使用Windows窗体计时器,则会在GUI线程上引发已发生的事件。如果您使用System.Threading.Timer
,则必须使用Invoke
,因为NSGaga会在答案中显示。
有关我不鼓励使用System.Timers.Timer
的原因的详情,请参阅Swallowing exceptions is hiding bugs。