4

i have problems with this timer, my function in the Tick event are appearing twice.. i want it to appear only once..

        public void timerStart()
        {
            DispatcherTimer updaterTimer = new DispatcherTimer();
            updaterTimer.Tick += new EventHandler(updaterTimer_Tick);
            updaterTimer.Interval = new TimeSpan(0,0,0,0,300);
            updaterTimer.Start();
        }

        private void updaterTimer_Tick(object sender, EventArgs e)
        {
           updaterTimer.Stop();
           checkSigningAvailable();
           updaterTimer.Start();
        }

This is the method that is checked every tick of the timer,

        public void checkSigningAvailable()
        {
           if (dt_signing_in.CompareTo(DateTime.Now) < 0)
           {
               if (!InPopAlready)
               {
                  InPopAlready = true;
                  disableSigningIn("False", this.event_id);
               }
           }
        }

And the messagebox in the bottom is appearing twice after calling this function above

        public void disableSigningIn(string Out,string event_id)
        {
           System.Console.WriteLine("POPED "+ InPopAlready);

           connection.Open();
           string sign = "True," + Out;
           string query = "update data_storage set data_details = '" + sign + "' where data_name = 'Signing';";
           NpgsqlCommand command = new NpgsqlCommand(query, connection);
           command.ExecuteNonQuery();
           connection.Close();
           sign_in.Content = "Sign-in Time : Over";
           string query2 = concatQuery(getIDnumberAttendance(event_id));
           updateAbsences(query2);

           MessageBox.Show("Signing in is over!", "No more signing in!", MessageBoxButton.OK, MessageBoxImage.Information);
}
Braudy
  • 181
  • 1
  • 11
  • 1
    Thats a pretty fast timer; how do you know its not just ticking twice? Can you show some code that shows the error? – BradleyDotNET Oct 22 '14 at 22:37
  • inside the Tick event, i have a function that pops up a message box if the condition is true, this is supposed to pop once, i already did flagging. The only error is , the message box pops twice .. i also tried slowing down the timer, but doesn't work .. – Braudy Oct 22 '14 at 22:47
  • Can you show the function? If you don't stop the timer, it could *still* tick twice. We appreciate the info, but there still isn't enough here to help. – BradleyDotNET Oct 22 '14 at 22:49
  • Please show a good code example (http://stackoverflow.com/help/mcve). Nothing you show here would cause the timer to stop running after the first interval, so while you're waiting for the user to dismiss the message box, it's entirely possible the timer is signaled again (and again, and again, and...) – Peter Duniho Oct 22 '14 at 22:51
  • Already edited the code .. please check thank you for your response – Braudy Oct 22 '14 at 23:02
  • @BradlyDotNET are these enough ? – Braudy Oct 22 '14 at 23:08
  • You call `Stop` twice is that the real code? Also, your "flag check" is vulnerable to a race condition; you may want to `lock` around that check. That code is *probably* enough, though I'm not sure it looks like the real code. – BradleyDotNET Oct 22 '14 at 23:10
  • I'm sorry, the second stop is supposed to be start. That codes are exactly what i got here. how do i lock these flag? – Braudy Oct 22 '14 at 23:16
  • Ok; how long of a timer have you tried? does it work if the timer is a second? You *could* be getting switched out right away, but its unlikely. I can give you the `lock` code (or just look up that keyword on MSDN) but I'd rather figure out if you are in a race condition first. – BradleyDotNET Oct 22 '14 at 23:24
  • I tried a second, but it doesn't work. Also tried 5 seconds still don't work. I did some googling, and they say that it is because of the += operator in initializing the tick event, they say if it is safe to use -= when using += , but i don't know where to put the -= operator. Anyway what do you mean by race condition ? I'm so sorry . Thank you for the help – Braudy Oct 22 '14 at 23:32
  • I only see one addition to `Tick`; do you do that line again anywhere, or call that function twice (`timer_start`)? That would cause the problem. When I say "race condition" I mean when two threads try to access/set a variable at the same time. Suffice it to say they are *really* hard to debug, and since threads are inherent to UI work, you end up having to learn some advanced concepts really early. – BradleyDotNET Oct 22 '14 at 23:34
  • I will try checking it, how about the lock ? – Braudy Oct 22 '14 at 23:36
  • `lock` is how you get out of race conditions (it implements a "Mutex"). Without writing a dissertation on threading, it would be a bit hard to explain. Look it up on MSDN if you are interested, and I'll try to explain it if you actually have a race condition. – BradleyDotNET Oct 22 '14 at 23:38
  • OMG i got it now, i called the function twice. . thanks for everything – Braudy Oct 22 '14 at 23:43
  • Just a tip, don't set `Tick` in a function that can get called multiple times like that. Set it in a initialization routine, or even the constructor. It helps avoid errors like this. – BradleyDotNET Oct 22 '14 at 23:46
  • Also check: http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlparameter%28v=vs.110%29.aspx . You should use parameters in your sql statements – blfuentes Oct 23 '14 at 10:43

4 Answers4

3

You are adding " += new EventHandler " and adding and adding new EventHandlers all over new EventHandlers but never remove them..

All the previous one gets fired each Time the Timer Starts again. You can reproduce this behaviour if you implement a counter, then you will see that is doubles with each new added and raised Event. (Edit: Just was confused because the "new" keyword, but actually I will not delete the answer since I am pretty sure that in some cases it will exactly be the issue)

The following may help: How to remove all event handlers from an event

And here the most easy solution: (You may polish it by using delegates)

Declaration in Class:

private System.Windows.Threading.DispatcherTimer P5DispatcherHelpsystemTimer = new System.Windows.Threading.DispatcherTimer();
private EventHandler P5DispatcherTimerHandler;

Dispatcher Timer Method:

private void InitializeHelpsystemCronjobs(System.Windows.Controls.Canvas sub_CanvasElement)
{
        P5DispatcherTimerHandler = (sender, e) => P5DispatcherHelpsystemTimerTick(sender, e, sub_CanvasElement);
        P5DispatcherHelpsystemTimer.Tick += P5DispatcherTimerHandler;
        P5DispatcherHelpsystemTimer.Interval = new TimeSpan(0, 0, 1);
        P5DispatcherHelpsystemTimer.Start();
}

Dispatcher TimerTick Method:

private void P5DispatcherHelpsystemTimerTick(object sender, EventArgs e, System.Windows.Controls.Canvas sub_CanvasElement)
{
    P5DispatcherHelpsystemTimer.Stop();
    {
       // Do stuff
    }
    P5DispatcherHelpsystemTimer.Start();
}

// Somewhere when an Trigger Event or Action etc. happens and the Timer shall start:

InitializeHelpsystemCronjobs(HelpsystemHelpCanvas);

// Somewhere when it sahll stop:

P5DispatcherHelpsystemTimer.Stop();
P5DispatcherHelpsystemTimer.Tick -= P5DispatcherTimerHandler;

(If you have more complex situation you definitely need delegate List<>)

Dororo
  • 41
  • 4
1

For me, it was not starting, stopping or the Timer at all. It was the DI/IOC container resolving two instances of the ViewModel which started a new refresh timer in the constructor. Check to make sure that you are always seeing the same ViewModel instance and not actually two separate ones, firing two separate Timers.

Michael K
  • 822
  • 11
  • 13
0

The code below fires the MessageBox only once:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        this.timerStart();
    }

    DispatcherTimer updaterTimer;
    private bool InPopAlready;
    DateTime dt_signing_in;

    public void timerStart()
    {
        updaterTimer = new DispatcherTimer();
        updaterTimer.Tick += new EventHandler(updaterTimer_Tick);
        updaterTimer.Interval = new TimeSpan(0, 0, 0, 0, 300);
        updaterTimer.Start();
    }

    private void updaterTimer_Tick(object sender, EventArgs e)
    {
        updaterTimer.Stop();
        checkSigningAvailable();
        updaterTimer.Start();
    }



    public void checkSigningAvailable()
    {
        if (dt_signing_in.CompareTo(DateTime.Now) < 0)
        {
            if (!InPopAlready)
            {
                InPopAlready = true;

                // Calling your method and showing MessageBox
                MessageBox.Show("Signing in is over!", "No more signing in!", MessageBoxButton.OK, MessageBoxImage.Information);
            }
        }
    }
}
Demir
  • 1,787
  • 1
  • 29
  • 42
0

I tend to write my "once-off" timer code like this:

var updaterTimer = new DispatcherTimer();
updaterTimer.Interval = new TimeSpan(0, 0, 0, 0, 300);
EventHandler tick = null;
tick = (s, e) =>
{
    updaterTimer.Stop();
    updaterTimer.Tick -= tick;
    /* execute once-off code here */
};
updaterTimer.Tick += tick;
updaterTimer.Start();

Then I don't need to fluff with making new methods - it's all in one local code block.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172