Click here to Skip to main content
15,922,427 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
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?
Posted

Two ways:
  1. Your Elapsed event handler method could be instance one (non-static). In this form, it will get access to the whole instance of its declaring class, via "this" parameter (keyword "this" could be omitted if there is no an ambiguity).
  2. Make a handler an anonymous method. It will allow you to use the closure feature. The closure will make even the local variable accessible beyond the lifetime of the method adding a handler to the timer's event invocation list. Please see:
    http://en.wikipedia.org/wiki/Closure_%28computer_science%29[^].

    Warning! Use with care, only when you understand well how it works.


Is it enough or do you need more detail? Please respond if you need them.

[EDIT]

As I can see, it still need some illustrations. First and foremost, instance handler:

C#
class Motor {

    System.Timers.Timer timer = new System.Timers.Timer();
    int valReg = 30;

    void timerHandler(object sender, System.Timers.ElapsedEventArgs e) {
        // ...
        this.valReg++; // as this method is an instance method,
                       // you can access it via the instance
        //...
        // same as
        valReg++; // this is needed just for understanging
                  // or if you need to resolve some ambiguity
    } //timerHandler

    void SomeTimerSettingMethod() { // could also be a constructor
        timer.Elapsed += timerHandler; // the new "System.Timers.ElapsedEventHandler"
                                       // ceremony is not really needed
        // ...
    } // SomeTimerSettingMethod

    //...

} // Motor


Now, the approach with closure. It's more delicate:
C#
class Motor {

    System.Timers.Timer timer = new System.Timers.Timer();
    int valReg = 30;

    void SomeTimerSettingMethod() { // could also be a constructor
        timer.Elapsed += (sender, eventArgs) => {
            valReg++; // you can just use it
        };
        // ...
    } // SomeTimerSettingMethod

    // ...

} // Motor


And, finally, the nice combination of anonymous method without direct access to the data members through the closure, but anonymous method freezes up the "real" handler from unused parameters:

C#
class Motor {

        System.Timers.Timer timer = new System.Timers.Timer();
        int valReg = 30;

        void TimerHandler() {
            valReg++; // you can just use it
        } //TimerHandler

        void SomeTimerSettingMethod() { // could also be a constructor
            timer.Elapsed += (sender, eventArgs) => { TimerHandler(); } // as simple as that
            // ...
        } // SomeTimerSettingMethod

        //...

} // Motor 


In most cases, I would prefer the last combined variant.

Any questions?

—SA
 
Share this answer
 
v3
Comments
Millone 4-Jun-13 13:07pm    
Thank you. Not easy to understand right now but I will study your advice and try to understand the dynamic.
Sergey Alexandrovich Kryukov 4-Jun-13 14:16pm    
Really? First item is really easy. Perhaps I'll need to add some illustrations. I just did not have a minute for that in first place.

First of all, don't pay attention if someone tells you that non-static method is not allowed as a handler. It is allowed and recommended, but not widely understood, just because this part of documentation is not clear enough.

Also, I want to warn you against Solution 1. Don't do it! It works but has so considerable drawbacks (and dangers) that I did not include it, as I consider it unacceptable (and, if used thoroughly, just redundant). I'll try to explain to Keith what's wrong, later, and then you can see it, too.

—SA
Millone 4-Jun-13 14:39pm    
Sergey, thanks. I will wait for some illustration to better understand your concept.
Sergey Alexandrovich Kryukov 4-Jun-13 15:10pm    
Already done. It's quite simple. I would advise the last variant.
—SA
Sergey Alexandrovich Kryukov 4-Jun-13 15:20pm    
And please also see my comments to Solution 1. It explains why you should not use it. Again, your follow-up questions are welcome.
—SA
Assuming I understand you correctly, I don't think you can make this work the way you are expecting (i.e. the values on the out parameter).

My solution:

Have specific, thread safe properties on the Motor class (e.g. CurrentPwmAuto & CurrentPreValReg )and raise an event when you update these. Probably "option b" will make more semantic sense at the class level, which is to create a separate class to contain the values of the update (Say it is called Foo, I'm assuming two properties PwmAuto and PreValReg). Then you can just raise the event directly, something like:

C#
class Motor
{
    public event Action<foo> Updated

    public static System.Timers.Timer _timer;
    int valReg = 30;
 
    public void PID(decimal _actualSpeed, Decimal _speedRequest)
    {
 
        _timer = new System.Timers.Timer();
        _timer.Interval = (3000);
        _timer.Elapsed += new System.Timers.ElapsedEventHandler(_timerAutoset);
        _timer.Enabled = true;
    }
    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
         */
       if(Updated!= null) //If null, no subscribers
       {
            Updated(new Foo() {PwmAuto = "whatever",  PreValReg = "whatever"});
       }
    }    
}</foo>


Then the UI will just need to subscribe to the event and update as necessary. Obviously all UI updates will need to be done on the UI thread, so you might need to marshal back on to it. I'd be surprised if there aren't other solutions, but this is where I'd start.
 
Share this answer
 
v2
Comments
Millone 4-Jun-13 13:08pm    
Thanks for now. I will study and try the advice.
Sergey Alexandrovich Kryukov 4-Jun-13 15:19pm    
Keith,

I hate to tell you that, but even though it would work, this is a pretty bad solution. You are introducing yet another static (instead of actually removing static from both timer and handler).

Static members (except some purely functional functions) are always bad unless absolutely required. This will work only as ad-hoc solution, with number of limitations. First of all, it will not work if you have several independent motors. You still need instances, and your solution won't help. Even if you use static for a reason, it makes the solution not thread safe (threads are a must in almost all hardware-controlling software, as in OP's case). Adding thread safety is possible, but then you would need to add thread synchronization. But best thread synchronization is no synchronization; and that is also a solution based on instance members only, and stack.

You did not explained the threading issues (even though you mentioned "marshaling"), but you should have explained it. Do you mean Invoke/PInvoke or something else? Just needed some explanation.

At the same time, some solutions based on instance member only are quite possible. And it also allows multiple Motor instance without additional precautions. I explained it in my answer, please see.

—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900