结束用户控件中的计时器操作



我在用户控件中结束计时器操作时遇到问题。我通过一些操作创建了用户控件,使用计时器间隔发生。我想实现这个目标:当用户使用我的用户控件关闭窗口时,操作(在 Calculate() 方法中)将停止。这是我在MyUserControl.cs的代码:

   // fields
   private Timer timer; 
    // ctor
    public TestUserControl()
    {
       InitializeComponent();
       timer = new Timer();   
       timer.Tick += timer_Tick;
       timer.Interval = 5000;
       timer.Start();
    }
    void timer_Tick(object sender, EventArgs e)
    {
        Compute();
    }
    void ParentForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        timer.Stop();
    }
    private static void Compute()
    {
       // do something
    }

InitializeComponent()方法中的这一行TestUserControl.Control.Desinger.cs

this.ParentForm.FormClosing += new System.Windows.Forms.FormClosingEventHandler(ParentForm_FormClosing);

但是我在这一行中得到异常:类型为"System.NullReferenceException"的未处理异常

当前尝试的主要问题是,当从构造函数调用 InitializeComponent() 方法时,控件还没有Parent值。这是异常告诉您的空值。

请参阅什么是 NullReferenceException 以及如何修复它?

解决此问题的最直接方法是首先删除所有Timer初始化代码和Timer字段,然后使用设计器将Timer添加到UserControl。然后,您甚至不必首先订阅父级的FormClosing事件。

您可以在设计器的"工具箱"窗口中的"组件"类别下找到Timer对象。您可以拖动或双击它以将其添加到UserControl,就像任何其他工具箱项一样。它不会被放置在UserControl本身上,而是放置在设计器自己的编辑窗口底部的区域供您UserControl。您可以在那里选择它并设置EnabledInterval等属性,以及为Tick事件添加事件处理程序。

如果将其配置为将 Enabled 属性设置为 true ,则它将在创建UserControl后立即启动。无论如何,通过以这种方式添加到UserControl,它最终出现在控件自己的组件列表中,并在释放UserControl本身时(即关闭父窗体时)自动释放(从而停止)。

请注意,正如"Idle_Mind"中的注释所指出的那样,由于Tick处理程序是在 UI 线程上执行的,因此 UI 线程在运行时不会发生任何其他操作。这意味着(除其他事项外)如果Compute()方法需要一些时间才能完成,则用户可能会察觉到从他们尝试关闭窗口到实际关闭窗口的延迟。

由于任何通常会发出关闭窗口信号的事件(例如鼠标单击、Alt+F4 等)在此期间甚至无法处理,因此确实没有好方法可以更改此行为(有一个不好的方法,我拒绝在这里描述)。在Compute()方法完成之前,您甚至不会从用户那里收到该信号。

如果您需要能够在 Compute() 方法运行时通过用户输入中断该方法,那么一种选择是使用 System.Windows.Forms.Timer 以外的某个计时器,以便计时器处理程序将在单独的线程上运行,并使 UI 线程响应用户输入。另一种选择是将 Compute() 方法更改为异步方法,这样即使计时器事件本身是在 UI 线程上处理的,数据库操作也会异步处理,而不会阻塞 UI 线程。任何一个选项都是另一个问题,为了得到一个好的答案,需要有关您的Compute()方法的特定详细信息,以显示您如何访问数据库和使用结果。:)

最新更新