In my form's class, I've added a method to "fade" it out. This makes use of System.Timers.Timer and the Elapsed event uses a delegate to change the form's opacity. This was the code:
public void FadeOut()
{
// Timer for transition
Timer fade = new Timer();
// Transition code
fade.Elapsed += delegate
{
this.Opacity += 0.05;
if (this.Opacity >= .95)
{
this.Opacity = 1;
fade.Enabled = false;
fade.Dispose();
}
};
fade.Interval = 100;
fade.Enabled = true;
}
This caused a "Cross-thread operation not valid" error, which is a common hurdle I see. So I looked around for solutions and the first ones to come up involved using .BeginInvoke and blocks of code to keep the call to the same thread as the control. But I found this looked really bulky, so I kept looking and then discovered the SynchronizingObject property of System.Timers.Timer. This seems better because it only needed one extra line of code:
// Timer for transition
Timer fade = new Timer();
fade.SynchronizingObject = this;
The code runs fine now. But I'm really confused, how come a lot of solutions are suggesting the use of BeginInvoke/Invoke when all that's needed is to set SynchronizingObject to the form control?
Mostly because it is pointless to use the property. Yes, it ensures that the Elapsed event handler runs on the UI thread. But now it just does the same thing as a System.Windows.Forms.Timer.
Not quite though, it is worse. Because it doesn't guarantee that Elapsed won't be called after you disable it. Disabling it doesn't flush any pending invokes nor TP threads that aren't ready to run yet. There could be hundreds if the Interval is small compared to the amount of work done by the handler.
You absolutely want a System.Windows.Forms.Timer here. You are not doing any useful work on the threadpool thread.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With