奇怪的Winforms Bug?

时间:2010-09-17 12:13:08

标签: c# winforms

我正在制作一个日历应用程序供我自己使用和学习。

到目前为止,我已经毫无困难地使用多种形式,并在彼此之上打开新的等等。

以下是一个例子:

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

无论如何,我现在开始添加计时器,以便在我日历上的重要事件发生之前弹出一个“提醒”表格(即等一小时等)。

代码在加载程序时设置定时器,然后在每个定时器过去时,这称为:

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

LazyTimer与System.Timers.Timer完全相同,除了添加的属性“ReferredEvent”,它引用了要提醒的日历事件。

MainForm.ShowReminder()如下:

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

奇怪的是ReminderForm崩溃了。我已经尝试过其他形式(例如CalendarEventForm,我知道它可以正常工作)并且它们也会崩溃。但是,当我尝试通过按下主窗体上的按钮来加载ReminderForm时,它可以正常工作。

为什么我的表单在被计时器(间接)加载时会崩溃?

3 个答案:

答案 0 :(得分:9)

简答:使用System.Windows.Forms.Timer,而不是System.Timers.Timer

原因是System.Timer.Timers类将在另一个线程上触发timer事件,并且您无法直接从主UI线程之外的其他线程执行UI操作。

答案 1 :(得分:6)

如果它正在包装System.Timers.Timer,它将在线程池线程上触发,这意味着你无法在那里进行UI操作。

改为使用System.Windows.Forms.Timer,或将System.Timers.Timer中的SynchronizingObject设置为UI对象,以便在UI线程上触发计时器。

编辑:另一点......我个人可能会使用lambda表达式或匿名方法作为计时器的Tick事件处理程序,以这种方式捕获相关事件,从而避免额外的类和< / em>额外的方法:

// Presumably we've got a local variable here, e.g. currentEvent
timer.Tick += delegate { mainForm.ShowReminder(currentEvent; };

答案 2 :(得分:0)

您遇到了线程问题。

使用System.Windows.Forms.Timer时请使用System.Windows.Forms

System.Timers.Timer不会在应用程序事件循环上调用事件,而是直接调用事件处理程序,在您的情况下,这导致表单不支持的跨线程操作,并且您的应用程序崩溃。

相比之下,System.Windows.Forms.Timer将无缝地融入System.Windows.Forms的组件模型中。