Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing variables to timer event in a class

I have a method in a class that receives and returns multiple parameters from/to Form1. I need to use a timed event to execute some code using those parameters. I have arranged this simplified code to show the dynamic:

class Motor
{
    public static System.Timers.Timer _timer;
    int valReg = 30;

    public void PID(decimal _actualSpeed, Decimal _speedRequest, out Decimal _pwmAuto, out decimal _preValReg)
    {

        _timer = new System.Timers.Timer();
        _timer.Interval = (3000);
        _timer.Elapsed += new System.Timers.ElapsedEventHandler(_timerAutoset);
        _timer.Enabled = true;
        // {....}
        _pwmAuto = valReg;
        _preValReg = valReg - 1;
    }
    static void _timerAutoset(object sender, System.Timers.ElapsedEventArgs e)
    {
        /* here I need to work with:
         _actualSpeed
         _speedRequest
         _pwmAuto
         _preValReg
        and send back the last two variables
         */
    }    
}

This is how I pass and receive the variables from Form1 button :

        private void button4_Click(object sender, EventArgs e)
        {
        // some code ................
        Motor mtr = new Motor();
        mtr.PID(speedRequest, actualSpeed, out pwmAuto, out xxx);
        //..more code

How can I pass/get back those parameters to/from _timerAutoset event?

like image 275
FeliceM Avatar asked Jun 03 '13 06:06

FeliceM


People also ask

What is timer interval in C#?

The Timer class in C# represents a Timer control that executes a code block at a specified interval of time repeatedly. For example, backing up a folder every 10 minutes, or writing to a log file every second. The method that needs to be executed is placed inside the event of the timer.

Which event handler is generated when timer is enabled?

Once the timer is enabled, it generates a tick event handler to perform any defined task in its time interval property.

How do I stop a timer elapsed event?

It will fire at the elapsed time. To avoid this happening set Timer. AutoReset to false and start the timer back in the elapsed handler if you need one. Setting AutoReset false makes timer to fire only once, so in order to get timer fired on interval manually start timer again.


3 Answers

I tend to solve this problem using anonymous delegates.

public void PID(decimal _actualSpeed, Decimal _speedRequest, out Decimal _pwmAuto, out decimal _preValReg)
{
    _pwmAuto = valReg;
    _preValReg = valReg - 1;

     // Because we cannot use [out] variables inside the anonymous degegates,
     // we make a value copy
     Decimal pwmAutoLocal = _pwmAuto;
     Decimal preValRegLocal = _preValReg;

    _timer = new System.Timers.Timer();
    _timer.Interval = (3000);
    _timer.Elapsed += (sender, e) => { HandleTimerElapsed(_actualSpeed, _speedRequst, pwmAutoLocal, preValRegLocal); };        
    _timer.Enabled = true;
    // {....}

}

static void HandleTimerElapsed(Decimal actualSpeed, Decimal speedRequst, Decimal pwmAuto, Decimal preValReg)
{
   // (...)
}

(You have to be mindful when the delegate accesses local variables from the enclosing block. Double-check the code to ensure the values stored in those variables will not change between the assignment of the event handler and the invocation of this handler).

like image 98
Andrew Shepherd Avatar answered Nov 03 '22 02:11

Andrew Shepherd


It seems these parameters are coming from somewhere else. One approach could be to pass a callback via delegate and use it to get the updated values from.

Another approach will be to make a class and pass it to Motor's constructor and use its reference in the _timerAutoset to get the updated values.

Using Delegates:

class Motor
{
    public static System.Timers.Timer _timer;
    int valReg = 30;
    public delegate TimerParam ParameterizedTimerDelegate();
    public static ParameterizedTimerDelegate TimerCallback { get; set; }

    public void PID()
    {
        _timer = new System.Timers.Timer();
        _timer.Interval = (3000);
        _timer.Elapsed += new System.Timers.ElapsedEventHandler(_timerAutoset);
        _timer.Enabled = true;
        // {....}
        //Param.PwmAuto = valReg;
        //Param.PreValReg = valReg - 1;
    }
    static void _timerAutoset(object sender, System.Timers.ElapsedEventArgs e)
    {
        TimerParam param = TimerCallback();
        /* here you can use:
         Param.ActualSpeed
         Param.SpeedRequest
         Param.PwmAuto
         Param.PreValReg
        */
    }
}

Using a shared instance:

class TimerParam
{
    public decimal ActualSpeed { get; set; }
    public decimal SpeedRequest { get; set; }
    public Decimal PwmAuto { get; set; }
    public decimal PreValReg { get; set; }
}

class Motor
{
    public static System.Timers.Timer _timer;
    int valReg = 30;
    public TimerParam Param { get; set; }

    public void PID(TimerParam param)
    {
        Param = param;

        _timer = new System.Timers.Timer();
        _timer.Interval = (3000);
        _timer.Elapsed += new System.Timers.ElapsedEventHandler(_timerAutoset);
        _timer.Enabled = true;
        // {....}
        Param.PwmAuto = valReg;
        Param.PreValReg = valReg - 1;
    }
    static void _timerAutoset(object sender, System.Timers.ElapsedEventArgs e)
    {
        /* here you can use:
         Param.ActualSpeed
         Param.SpeedRequest
         Param.PwmAuto
         Param.PreValReg
        */
    }
}

You can then update the instance of TimerParam that you passed to the Motor class and timer will always get the updated values.

like image 35
Ali Avatar answered Nov 03 '22 03:11

Ali


you could try using lambda expression for inserting additional arguement..

  _timer.Elapsed += (sender, e) => _timerAutoset(sender, e, _actualSpeed,_speedRequest);

your method be like

static void _timerAutoset(object sender, System.Timers.ElapsedEventArgs e,decimal speed,decimal speedRequest)
like image 28
Rahul Avatar answered Nov 03 '22 04:11

Rahul