How do I pass an object into a timer event?

C#Timer

C# Problem Overview


Ok so I am using System.Timers.Timer in .Net 4 with C#.

I have my timer object like so:

var timer = new Timer {Interval = 123};

I have my Timer Elapsed event handler pointed at a method like so:

timer.Elapsed += MyElapsedMethod;

And my method looks like this:

static void MyElapsedMethod(object sender, ElapsedEventArgs e)
{
    Console.WriteLine("Foo Bar");
}

I want to pass a string into this method, how do I do this?

Thanks

C# Solutions


Solution 1 - C#

The easiest way to do this is to change the event handler into an anonymous function. It allows you to pass the string at the point of declaration.

string theString = ...;
timer.Elapsed += (sender, e) => MyElapsedMethod(sender, e, theString);

static void MyElapsedMethod(object sender, ElapsedEventArgs e, string theString) {
  ...
}

Solution 2 - C#

If you want to be able to unregister your "Elapsed" event handler again, you shouldn't use a delegate without remembering it in a variable.

So another solution could be to create a custom class based on Timer. Just add whatever members you like and get your custom Timer object back from the "sender" argument of the "Elapsed" event handler:

class CustomTimer : System.Timers.Timer
{
	public string Data;
}

private void StartTimer()
{
	var timer = new CustomTimer
	{
		Interval = 3000,
		Data = "Foo Bar"
	};

	timer.Elapsed += timer_Elapsed;
	timer.Start();
}

void timer_Elapsed(object sender, ElapsedEventArgs e)
{
	string data = ((CustomTimer)sender).Data;
}

This strategy of course works for other events and classes too, as long as the base class is not sealed.

Solution 3 - C#

You can save string in some object and read it in event handler:

static string _value;

static void MyElapsedMethod(object sender, ElapsedEventArgs e)
{
    Console.WriteLine(_value);
}

UPDATE: same code via different syntax: timer.Elapsed += (s,e) => Console.WriteLine(_value);

UPDATE: Consider also using System.Threading.Timer instead

State state = new State();
Timer timer = new Timer(OnTimer, state, 0, 123);
state.Value = "FooBar"; // change state object

You can retrieve state in timer callback:

static void OnTimer(object obj)
{
    State state = obj as State;
    if (state == null)
        return;        

    Console.WriteLine(state.Value);
}

Solution 4 - C#

 Timer aTimer = new Timer(300);
                aTimer.Elapsed += delegate { PublishGPSData(channel, locationViewModel); };
                // Hook up the Elapsed event for the timer. 
                aTimer.AutoReset = true;
                aTimer.Enabled = true;
private void PublishGPSData(IModel channel, LocationViewModel locationViewModel)
{
};

Solution 5 - C#

Use a field in the same class to hold whatever string you want and then retrieve it in you elapsed event handler. You'll have to be careful about cross-threading issues however.

Solution 6 - C#

I wrote this simple class to handle this:

using System;
using System.Timers;

namespace MyProject.Helpers
{
    public class MyTimer
    {
        private volatile Timer _timer = new Timer();
        private volatile bool _requestStop = false;
        private MyElapsedEventHandler _eventHander;
        private MyElapsedEventHandlerWithParam _eventHandlerWithParam;
        private object _param;

        public MyTimer(int interval, MyElapsedEventHandler elapsedEventHandler, bool autoReset = false)
        {
            _timer.Interval = interval;
            _timer.Elapsed += ElapsedWrapper;
            _timer.AutoReset = autoReset;

            _eventHander = elapsedEventHandler;

            Start();
        }

        public MyTimer(int interval, MyElapsedEventHandlerWithParam elapsedEventHandler, object param, bool autoReset = false)
        {
            _timer.Interval = interval;
            _timer.Elapsed += ElapsedWrapperWithParam;
            _timer.AutoReset = autoReset;

            _eventHandlerWithParam = elapsedEventHandler;
            _param = param;

            Start();
        }

        private void ElapsedWrapper(object sender, ElapsedEventArgs e)
        {
            if (!_requestStop && _eventHander != null)
            {
                _eventHander();
            }
        }

        private void ElapsedWrapperWithParam(object sender, ElapsedEventArgs e)
        {
            if (!_requestStop && _eventHandlerWithParam != null)
            {
                _eventHandlerWithParam(_param);
            }
        }

        public void Stop()
        {
            _requestStop = true;
            _timer.Stop();
        }

        public void Start()
        {
            _requestStop = false;
            _timer.Start();
        }
    }

    public delegate void MyElapsedEventHandlerWithParam(object param);
    public delegate void MyElapsedEventHandler();
}

use it like this:

void Main(string[] args){
    new MyTimer(durationInSeconds * 1000, EventHandler, "some string");
}

void EventHandler(object param){
    doSomethingWithString((string)param);
}

you can also pass the event arguments or any kind of parameters if you edit the delegate (and the call of the event handler in MyTimer class).

Solution 7 - C#

Why not just use a Timer and an ElapsedEventHandler?

namespace TimerEventHandler
{
    class Program
    {
        private static Timer myEventTimer;

        static void Main(string[] args)
        {
            // 5 second timer multiply 1000 milliseconds by the time
            //e.g. new Timer(60 * 1000 * 10) = 10 minutes
            myEventTimer = new Timer(5 * 1000 * 1);
            myEventTimer.Enabled = true;
            myEventTimer.Elapsed += new ElapsedEventHandler(TimerSchedule_Elapsed);

            Console.WriteLine("Timer started!");

            // make a thread and wait forever just so console does not go away
            Thread.Sleep(Timeout.Infinite);
        }

        private static void TimerSchedule_Elapsed(object sender, ElapsedEventArgs e)
        {
            // do something
            Console.WriteLine("Timer elapsed!");
        }
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJMKView Question on Stackoverflow
Solution 1 - C#JaredParView Answer on Stackoverflow
Solution 2 - C#Michael GeierView Answer on Stackoverflow
Solution 3 - C#Sergey BerezovskiyView Answer on Stackoverflow
Solution 4 - C#MahendraView Answer on Stackoverflow
Solution 5 - C#Matt BurlandView Answer on Stackoverflow
Solution 6 - C#lennyView Answer on Stackoverflow
Solution 7 - C#Michael BrownView Answer on Stackoverflow