0

I need to run a method every 5 seconds in a c# console program (this program opens a Win form UI in a separate thread).

Every attempt I have had at creating timer has failed due to the eventhandler not being killed off after each time the _timer.Elapsed (or _timer.Tick) reaches 0.

This is resulting in multiple calls to my method, and subsequently the information I'm collection gets duplicated (3 times for each eventhandler).

Does anyone have an example of a way I can call my method every 5 seconds, that wont result in this duplication?

   public static System.Timers.Timer _timer = new System.Timers.Timer();


    static void Main(string[] args)
    {
        //Check Registry for existing Robo config
        RegistryTasks StartupRegistryCheck = new RegistryTasks();
        StartupRegistryCheck.StartupRegistryCheck();

        RetrieveJobs();

        _timer.Interval = 5000;
        _timer.Elapsed += OnTimedEvent;
        _timer.Enabled = true;

        new Thread(() =>
        {
            //Thread.Sleep(6000);
            load_UI();
        }).Start();
    }

    static void RetrieveJobs()
    {
        RegistryTasks getIPs = new RegistryTasks();
        getIPs.GetIPFromRegistry(Servers);
        //Console.WriteLine(Servers);
        foreach (object o in Servers)
        {
            dynamic expObj = new ExpandoObject();
            expObj = o;
            string IP = expObj.serverObjectIp;
            int Port = expObj.serverObjectPort;

            // Start synchronous socket connections
            string JobList = SocketClient.GetJobList(IP, Port);

            // Uncomment the lines below to use async sockets (currently not working)
            // IPHostEntry ipHostInfo = Dns.GetHostEntry(IP);
            // IPAddress ipAddress = ipHostInfo.AddressList[0];
            // IPEndPoint ipe = new IPEndPoint(ipAddress, Port);
            // Socket s = new Socket(AddressFamily.InterNetwork,
            // SocketType.Stream, ProtocolType.Tcp);
            // string JobList = ClientSocketAsync.Connect(ipe, s);

            // Split Retrieved JobLiST XML data into Arrays for later use.
            XmlSplitter.splitXml(JobList, out ActiveJobsArray, out CompletedJobsArray, out PendingJobsArray);
        }
    }

    public static void OnTimedEvent(object source, System.Timers.ElapsedEventArgs e)
    {
        _timer.Stop();
        RetrieveJobs();
        _timer.Start();
    }

The code in question is above :(

Current output... below.

Timer hit 0.
Received data 1
Received data 2
Received data 3
Timer hit 0.
Received data 1
Received data 2
Received data 3
Received data 1
Received data 2
Received data 3
Timer hit 0.
Received data 1
Received data 2
Received data 3
Received data 1
Received data 2
Received data 3
Received data 1
Received data 2
Received data 3

Update... So I still haven't figured out why my timer wont work without duplicating itself. Main is only called once. there are no other references to a timer in any other classes. The only reference or hint of a timer is found in the code previously mentioned.

So, as an experiment to see if it is cured in a new program, I created a new console application.

I added a timer, and a "MessageBox.Show()" to block the program and prevent an exit. 100% of the code written for this test can be found below, strangely, the program exits immediately, and no MessageBox is displayed. The timer doesn't even perform one loop (as it would be expected to with AutoReset set to false).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ConsoleApplication1
{
    class Program
    {
        public static System.Timers.Timer _timer = new System.Timers.Timer();

    static void Main(string[] args)
    {
        _timer.AutoReset = false;
        _timer.Interval = 5000;
        _timer.Elapsed += OnTimedEvent;
        _timer.Enabled = true;
        _timer.Start();
    }

    static void OnTimedEvent(object source, System.Timers.ElapsedEventArgs e)
    {
        _timer.Stop();
        Console.WriteLine("Timer Stopped");
        //_timer.Elapsed -= OnTimedEvent;
        RetrieveJobs();
        _timer.Start();
        Console.WriteLine("Timer Started");
    }

    static void RetrieveJobs()
    {
        Console.WriteLine("Timer hit 0");
        MessageBox.Show("Blocking Timer Program Exit for Timer to run!");
    }
    }
}

This is now resolved. Please close.

Turns out my Servers object in the RetrieveJobs() foreach loop is getting duplicated. Instead of listing 3 servers, its collection those same 3 servers from the registry and adding them to the object. My own fault for not spotting this sooner. Thanks to all who offered help though :).

user2295457
  • 101
  • 11
  • have you thought about `_timer.Elapsed -= OnTimedEvent;` to get rid of the created event.. – MethodMan Feb 06 '15 at 14:13
  • adding a _timer.Elapsed -= OnTimedEvent only seems to server the purpose of stopping the timer altogether. I'm unclear as to why though :( – user2295457 Feb 06 '15 at 14:14
  • 2
    Grant is correct, there is no error in code you showed. Problem lies somewhere else, put cursor on `_timer.Elapsed` and hit shift+F12 (Find references). – PTwr Feb 06 '15 at 14:18
  • I added the "Timer Hit 0" & "Received Data X" only as an example of the output (its not whats really being output, but was the easiest way of reflecting it). And that's my problem, as far as I'm aware this should work as intended, so the output has completed thrown me. – user2295457 Feb 06 '15 at 14:18
  • Hitting that button combo shows only what I expected... 7 symbol matches found. All of them detailed in the above code. – user2295457 Feb 06 '15 at 14:24
  • It only breaks once with a break point set on that line. Yet the output is being duplicated at the same time. Also adding a "_timer.Elapsed -= OnTimedEvent;" directly after the current "_Timer.Stop();" only seems to server the purpose of stopping the timer after it hits 0 for the first time :/ – user2295457 Feb 06 '15 at 14:28
  • load_UI opens a Windows Form on another thread. the remainder is being called from .cs files but being called / run in the console application. – user2295457 Feb 06 '15 at 14:36
  • A little context about the application. I'm getting info from an external source in the form of XML strings. This is then sent to an xml parser, that splits the received data into workable objects, all saved in arraylists for use on the UI thread. – user2295457 Feb 06 '15 at 14:39

0 Answers0