c# timer strange behavior - c#

private void aMethod()
{
aTimer = new System.Timers.Timer(3000);
aTimer.Elapsed += new ElapsedEventHandler(OnTimerEvent);
aTimer.Enabled = true;
aTimer.Start();
}
private void button4_Click(object sender, RoutedEventArgs e)
{
fileEntries = Directory.GetFiles(#"C:\Users\John\Documents\Visual Studio 2010\Projects\ComeOn\ComeOn\bin\Debug\come");
aMethod();
index = 0;
}
private void OnTimerEvent(Object sender, ElapsedEventArgs e)
{
Bitmap LogoImg = new Bitmap(fileEntries[index]);
LogoImg.MakeTransparent(LogoImg.GetPixel(1, 1));
this.Dispatcher.Invoke(
new Action(() => image1.Source = GetBitmapSource(LogoImg)));
index++;
}
The length of fileEntries is 3. I created a timer which will start on 3 seconds. First it will execute image1.Source = GetBitmapSource(LogoImg)//for fileEntries[0] for 3 seconds, then for fileEntries[1] for 3 seconds and in the end fileEntries[2] for 3 seconds.
But, my program does this:
Start the timer, run fileEntries[0], fileEntries[1] and fileEntries[2] for 0.05 seconds, then wait 3 seconds, then start again. Why is this?

How often did you click that button?
Every time you press the button, a new event handler will be hooked to the timer. You never unsubscribe the event handler.
You should either prevent the button from being clicked while you are performing the required work, or you should unsubscribe before subscribing again.
As Hans Passant states in his comment, you should probably also look into using a BackgroundWorker.

You shouldn't do
aTimer = new System.Timers.Timer(3000);
aTimer.Elapsed += new ElapsedEventHandler(OnTimerEvent);
aTimer.Enabled = true;
aTimer.Start();
more than once. Do it in Form_Load event, or in constructor. in your OnTimerEvent event, prevent your code from being executed when files aren't initialized, for example
int index = -1;
private void OnTimerEvent(Object sender, ElapsedEventArgs e)
{
if(index != -1)
{
Bitmap LogoImg = new Bitmap(fileEntries[index]);
LogoImg.MakeTransparent(LogoImg.GetPixel(1, 1));
this.Dispatcher.Invoke(
new Action(() => image1.Source = GetBitmapSource(LogoImg)));
index++;
}
if (index == 3) // when all 3 were loaded, reset index. You can also stop the timer if you won't be loading files the second time
{
index=-1;
}
}
Or you should unsuscribe before you add new event handler. But keeping track of how many event handlers are added to an event is tricky (or I should say I havn't found a way to do it yet).
As #Steven Jeuris said, when an event handler is added to an event, it is literaly ADDED, to event handlers LIST. So every time when your timer elapses every event handler on the list is executed, which means if there are 3 event handlers added (as in your case) the event handler method will execute 3 times.

Related

How to get list index of Timer object list in Timer Event Handler

My application requires 22 separate timers. So I created a timer list like so.
List<Timer> myTimers = new List<Timer>();
for(int i = 0; i < 22; i++)
{
myTimers.Add(new Timer());
}
Then I set settings for the timers
foreach(var timer in myTimers)
{
timer.Elapsed += new ElapsedEventHandler(ElapsedTimerEventHandler);
timer.Interval = 10000;
timer.Enabled = false;
}
I then created a method to start the timer.
public void SetTimerMethod(int timerId)
{
var timer = myTimers.ElementAt(timerId);
timer.Enabled = true;
}
My question is in my Event Handler how do I find out which timer called the event handler. I tried using indexOf(myTimers); on the source object passed to the event handler but that does not work. The reason I need the index position is because I need to update a field in a list of class objects based upon which timer expired. Any help would be appreciated.
I am new to this so I am open to doing this in a different way if this is a bad way of doing what I want to.
If you really want the index and not just the timer, you could use IndexOf
private ElapsedEventHandler(object sender, ElapsedEventArgs e)
{
var index = myTimers.IndexOf((Timer)sender);
}
If every timer has the same interval and is started the same time what is the point of having many of them versus one? Anyway, the sender property of the Elapsed event is the source timer (see also the docs:
private void ElapsedTimerEventHandler(Object source, System.Timers.ElapsedEventArgs e)
{
var timerCausingThisEvent = (Timer)source; // source is the timer
var timerInList = myTimers.First(t => t == timerCausingThisEvent);
var index = myTimers.IndexOf(timerCausingThisEvent);
}

How to use properly Timer Object?

I have this code behind in asp.net page:
protected void LoadFile(object sender, EventArgs e)
{
try
{
Timer myTimer = new Timer();
myTimer.Elapsed += new ElapsedEventHandler( RemoveFile );
myTimer.Interval = 60000;
myTimer.Start();
}
catch (Exception)
{
}
}
private void RemoveFile(object source, ElapsedEventArgs e)
{
string path = UniquePath();
File.Delete(path);
}
When LoadFile event handler fired the RemoveFile function fired after 60 sec(as defined in this row myTimer.Interval = 60000), if LoadFile fired again after 40 seconds the RemoveFile will fire in 20 seconds.
My question is how to make the RemoveFile function to be activated after 60 seconds from last call of the LoadFile event hanlder?
May be you could use
myTimer.Stop(); just after Timer myTimer = new Timer();
I would use Microsoft's Reactive Extensions (NuGet "Rx-Main") for this. The code becomes:
private SerialDisposable _serialDisposable = new SerialDisposable();
protected void LoadFile(object sender, EventArgs e)
{
_serialDisposable.Disposable =
Observable
.Interval(TimeSpan.FromSeconds(60.0))
.Subscribe(n =>
{
string path = UniquePath();
File.Delete(path)
});
}
Now, observables are like events and calling .Subscribe is like attaching to an event. The .Subscribe call returns an IDisposable which you can use to detach from the observable by calling .Dispose(). The SerialDisposable object is a special disposable class provided by Rx that lets you assign new disposables and automatically dispose any previously assigned disposables. This automatically resets the timer every time LoadFile is run.
This is just one use of Rx - it has so many more uses and is very powerful and worth learning.

What event is responsible for actions when time is out in Timer Control?

My program is some kind of test. The time of passing test is limited(20 minutes). When the time is out, the test must be finished and MessageBox appears with results of test. In Form_Load :
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = (1000) * (1);
timer1.Enabled = true;
timer1.Start();
private void timer1_Tick(object sender, EventArgs e)
{
timer_label.Text = Convert.ToString(time);
--time;
}
How to finish test when time == 0? And why time in timer_label changes with step 2?(e.g. 1999, 1997, 1995...)
How to finish test when time == 0?
Timer just raises even on some interval. You should start timer for that. If you don't want events to be raised anymore, you should stop timer. You can do it directly in Tick event handler:
private void timer1_Tick(object sender, EventArgs e)
{
timer_label.Text = Convert.ToString(time);
time--;
if (time == 0)
timer1.Stop();
}
Second question:
And why time in timer_label changes with step 2?(e.g. 1999, 1997,
1995...)
From your code there is no reason for such behavior. Looks like you have subscribed to two timers, or you have two event handlers of same timer Tick event. Also make sure you don't have decrement operator when displaying time, something like this:
timer_label.Text = Convert.ToString(--time);
--time;

C# Timer not resetting from one click to another

I need to store the piano duration with Ticks as so then make the music note show according to that duration (Music players would know).
I'm using an interval of 100, but for some testing I used it at 1000.
The problem is this. When I'm invoking the method (I'm taking the 1000 millisecond interval one) the timer starts.. if I DO NOT manage to get the 1000 milliseconds it shows Duration 0: but then if I do for example 2 seconds, it shows 3 seconds, if I try to press it for another second (a different key) it would show 4 seconds instead of 1.
It's like it keeps on recurring. Same happened with the 100 interval one. It went mad. sometimes 40 sometimes 23 and so on. Any idea how to fix (resetting the timer)
N.B I'm using System.Windows.Forms.Timer as library
part of a method which invokes the methods further below
for (int i = 0; i < 15; i++)
{
WhiteKey wk = new WhiteKey(wKeys[i], wPos[i]-35,0); //create a new white Key with [i] Pitch, at that x position and at y =0 position
wk.MouseDown += onRightClick; //holds the Duration on Right Click
wk.MouseUp += onMouseUp;
wk.Click += new EventHandler(KeyClick); //Go to KeyClick Method whenever a key is pressed
this.panel1.Controls.Add(wk); //Give it control (to play and edit)
}
Methods controlling the time
private void onRightClick(object sender, MouseEventArgs e)
{
wk = sender as WhiteKey;
duration = 0;
t1.Enabled = true;
t1.Tick += timeTick;
t1.Interval = 100;
}
private void timeTick(object sender, EventArgs e)
{
duration++;
}
private void onMouseUp (object sender, MouseEventArgs e)
{
t1.Enabled = false;
String time = "Key: " + pitch + "\nDuration: " +duration ; //Test purposes to see if timer works
MessageBox.Show(time);
}
You are trying to measure time, don't use Timer, use Stopwatch.
You can find C# Stopwatch Exmples at dotnetpearls.com.
In abstract this is what you would want to do is something like this:
private void onRightClick(object sender, MouseEventArgs e)
{
stopwatch.Reset();
stopwatch.Start();
}
private void onMouseUp (object sender, MouseEventArgs e)
{
stopwatch.Stop();
String msg = "Duration in seconds: " + (stopwatch.ElapsedMilliseconds / 1000.0).ToString("0.00");
MessageBox.Show(msg);
}
Note: you may want to change the units or the string format.
Notes on using timer:
1) System.Windows.Forms.Timer uses the message loop of your window, this means that it may get delayed because the window is busy handling other events (such as click). For a better behaviour use System.Threading.Timer.
2) If using System.Windows.Forms.Timer don't set the Tick event handler each click. The event handler will execute once for each time you add it.
That is:
private void onRightClick(object sender, MouseEventArgs e)
{
wk = sender as WhiteKey;
duration = 0;
t1.Enabled = true;
//t1.Tick += timeTick; you should add this only once not each click
t1.Interval = 100;
}
3) If you use System.Threading.Timer you may want to make the variable duration volatile.
t1.Tick += timeTick;
By the way in your code sample you subscribe to the 'Tick' timer event each time on Right mouse click.
So if you click 2 times the
private void timeTick(object sender, EventArgs e)
method will be called twice, and 'duration++' will be executed twice. Your event subscription code should be executed only once for the timer.
P.S. If you need to measure duration, Timer is not the best way to do it.

How does the dispatcher timer perform its work in the tick event if another event happens in between? What is wrong with this code?

I've spent the last few days looking at the DispatcherTimer and I still can't wrap my head around some stuff. Here's what I understand so far,
the tick event will not occur twice at the same time link
there is no need to worry about the owner thread(s) of the objects
since the dispatcher timer automatically performs all the work in
the UI thread
the timing of the ticks may not be very accurate since the ticks are essentially executed from a queue
Now what I'm not clear about is the order of the code being executed if there is another event which runs in between a tick event. I've a test WPF application which uses a DispatcherTimer whose tick event performs 2 functions. firstStep() and secondStep() in sequence.
The firstStep()sets a variable to null while secondStep() sets it to a value that is not null. After setting the value, secondStep() will begin a storyboard which has a Completed event, which attempts to access this variable.
So my question is, is it possible for the Completed event to come in between the firstStep() and secondStep() function if we keep the timer running? I've written a test application and it seems to be that case, eventually we will reach a state where the variable is null when the Completed event gets executed. But I don't understand how that can happen, since firstStep() and secondStep() get executed in sequence, there should be no way the Completed event can be executed between the 2 functions (or I am wrong here). Does the UI thread execute the tick and the Completed event in parallel?
Can someone explain to me in detail how the UI thread executes events such as the example's storyboard completed event and dispatcherTimer's ticks in sequence? Thanks for reading, your comments are very much appreciated I'm trying very hard to get my head around this. The following is the test code I used, it will eventually throw an error after running for a while.
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
storyBoardTest = new Storyboard();
storyBoardTest.Completed += new EventHandler(storyBoardTest_Completed);
DoubleAnimation animation = new DoubleAnimation(1, 0.9, new Duration(TimeSpan.FromSeconds(1)));
Storyboard.SetTarget(animation, this);
Storyboard.SetTargetProperty(animation, new PropertyPath(UIElement.OpacityProperty));
storyBoardTest.Children.Add(animation);
DispatcherTimer dt = new DispatcherTimer();
dt.Interval = TimeSpan.FromMilliseconds(500);
dt.Tick += new EventHandler(dt_Tick);
dt.Start();
}
private Window windowTest = null;
private Storyboard storyBoardTest = null;
void dt_Tick(object sender, EventArgs e)
{
firstStep();
secondStep();
}
private void firstStep()
{
windowTest = null;
}
private void secondStep()
{
windowTest = this;
storyBoardTest.Stop();
storyBoardTest.Begin(this);
}
void storyBoardTest_Completed(object sender, EventArgs e)
{
//Attempt to access object throws null error. Why?
windowTest.Title = "test";
windowTest = null;
}
}
CallStack:
WpfApplication1.exe!WpfApplication1.Window1.storyBoardTest_Completed(object sender = {System.Windows.Media.Animation.ClockGroup}, System.EventArgs e = null) Line 63 C#
PresentationCore.dll!System.Windows.Media.Animation.Clock.FireEvent(System.Windows.EventPrivateKey key) + 0x5b bytes
PresentationCore.dll!System.Windows.Media.Animation.Clock.RaiseAccumulatedEvents() + 0x160 bytes
PresentationCore.dll!System.Windows.Media.Animation.TimeManager.RaiseEnqueuedEvents() + 0x60 bytes
PresentationCore.dll!System.Windows.Media.Animation.TimeManager.Tick() + 0x28a bytes
PresentationCore.dll!System.Windows.Media.MediaContext.RenderMessageHandlerCore(object resizedCompositionTarget) + 0xbc bytes
PresentationCore.dll!System.Windows.Media.MediaContext.AnimatedRenderMessageHandler(object resizedCompositionTarget) + 0x9d bytes
Every 500 milliseconds you are starting a Storyboard that runs for one second. This will inevitably lead to two consecutive Completed events without an intermediate Tick event.
Therefore you have to check if windowTest is already null in your Completed handler :
void storyBoardTest_Completed(object sender, EventArgs e)
{
if (windowTest != null)
{
windowTest.Title = "test";
windowTest = null;
}
}
Even if the Storyboard would run for less than 500 milliseconds there would be problem. As Storyboard.Completed events are appended to the Dispatcher queue in the same way as DispatcherTimer.Tick events and the timings of both DispatcherTimer and Storyboard are not exact, the execution order of the two event handlers is not reliable. Hence two Completed events may occur without an intermediate Tick event.
You may add some trace output to see that both handlers run in the same thread.
void dt_Tick(object sender, EventArgs e)
{
Trace.TraceInformation("Tick: {0}", Thread.CurrentThread.ManagedThreadId);
...
}
void storyBoardTest_Completed(object sender, EventArgs e)
{
Trace.TraceInformation("Completed: {0}", Thread.CurrentThread.ManagedThreadId);
...
}

Categories