I have attempted to create a derived class of Timer that allows for a 'Pause' latch to be set to keep the worker thread from reactivating the timer. However, Elapsed events are continued to be raised when AutoReset is set to false and the Enabled accessor appears to be doing it's job in preventing the Enabled property of the base class from being modified once the Paused variable is set.
Why is this happening or what strategies should I use to further understand what interactions are actually happening here?
I have attached the implementation of the derived class below.
using System.Timers
class PauseableTimer : Timer
{
public bool Paused;
new public bool Enabled
{
get
{
return base.Enabled;
}
set
{
if (Paused)
{
if (!value) base.Enabled = false;
}
else
{
base.Enabled = value;
}
}
}
}
Example illustrating problem.
class Program
{
private static PauseableTimer _pauseableTimer;
private static int _elapsedCount;
static void Main(string[] args)
{
_pauseableTimer = new PauseableTimer(){AutoReset = false,Enabled = false,Paused = false};
_pauseableTimer.Elapsed += pauseableTimer_Elapsed;
_pauseableTimer.Interval = 1;
_pauseableTimer.Enabled = true;
while(_elapsedCount<100)
{
if (_elapsedCount > 50) _pauseableTimer.Paused = true;
}
}
static void pauseableTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine(String.Format("this.Enabled:'{0}',Paused:'{1}',AutoReset:'{2}",_pauseableTimer.Enabled,_pauseableTimer.Paused,_pauseableTimer.AutoReset));
_elapsedCount++;
_pauseableTimer.Interval = _pauseableTimer.Interval == 1 ? 2 : 1; //This line breaks it.
_pauseableTimer.Enabled = true;
}
}
Relevant document, System.Timers.Timer.Interval
The recommended solution of setting
AutoReset
to true does not solve the problem because there is an undocumented behavior of settingAutoReset
to true during an event handler also allowing for an event to be fired.The solution seems to be to build out the derived object to the point where you can keep any of the apparently many ways that an event can be fired again from happening.
Below is the implementation that I ended with.
Another option is to suppress the event??? I can't explain what is going but the theory presented below should allow you to circumvent this little problem you have discussed. As Steve mentioned put a 'Watch and break point on the enabled property' that you are try set and make sure it is actually being set.
How would I tackle this:
Catch and check for the 'Enabled' property and remove '-=' the subscribing method (handler) as of when needed and then re-add '+=' it again when you do need handle the 'Elapsed' event.
I have used this style quite a few times on a few different WinForms project. If you don't want the 'Elapsed' event to be handled programmatically create a check for and remove it when a certain condition is met and then add it when the opposite condition is met.
The above code logic will allow you code to ignore the 'Elapsed' event ever time it is raised whilst the 'Paused' flag is true. I hope the above helps
I would reformat your code:
Not only does it read better, you can put a break point on the key line and see if it's being executed
Everything is more complex in multithreading, I'm afraid. Assuming your code is working as you wish, there is a window where in-flight events can get raised after you reset the
Enabled
property. See this quote from the MSDN docs.