The main problem with your current attempt is that when the InitializeComponent()
method is called, from the constructor, the control does not yet have a Parent
value. That's the null value the exception is telling you about.
See What is a NullReferenceException and how do I fix it?
The most straightforward way to address this would be first to remove all of the Timer
initialization code, and the Timer
field as well, and then to use the Designer to add the Timer
to your UserControl
. Then you don't even have to subscribe to the parent's FormClosing
event in the first place.
You can find the Timer
object in the Designer's Toolbox window, under the category of "Components". You can drag or double-click it to add it to your UserControl
just like any other Toolbox item. Instead of being placed on the UserControl
itself, it will be placed in an area at the bottom of the Designer's own editing window for your UserControl
. You can select it there and set properties like Enabled
and Interval
, as well as add an event handler for the Tick
event.
If you configure it to have the Enabled
property set to true
, then it will start as soon as your UserControl
is created. Regardless, by adding to the UserControl
in this way, it winds up in the control's own list of components and will be automatically disposed (and thus stopped) when the UserControl
itself is disposed, i.e. when the parent form is closed.
Do note that as the comment from "Idle_Mind" points out, because your Tick
handler is executed on the UI thread, nothing else will happen on the UI thread while it's running. This means (among other things) that if the Compute()
method takes some time to complete, the user could perceive a delay from when they try to close the window and when it actually is closed.
Since any event (e.g. mouse click, Alt+F4, etc.) that would normally signal the window to close can't even be processed during this time, there's really no good way to change this behavior (there's a bad way, which I refuse to describe here). You won't even receive that signal from the user until the Compute()
method has completed.
If you need to be able to interrupt the Compute()
method via user input while it's running, then one option would be to use some timer other than System.Windows.Forms.Timer
, so that the timer handler will run on a separate thread and leave the UI thread responsive to user input. Another option would be to change the Compute()
method to an async method so that even though the timer event itself is handled on the UI thread, the database operation is handled asynchronously without blocking the UI thread. Either option would be a whole other question, and for a good answer there would require specific details about your Compute()
method showing how you're accessing the database and using the results. :)