131

I have the following EventHandler to which I added a parameter MusicNote music:

public void PlayMusicEvent(object sender, EventArgs e,MusicNote music)
{
    music.player.Stop();
    System.Timers.Timer myTimer = (System.Timers.Timer)sender;
    myTimer.Stop();
}

I need to add the handler to a Timer like so:

myTimer.Elapsed += new ElapsedEventHandler(PlayMusicEvent(this, e, musicNote));

but get the error:

"Method name expected"

EDIT: In this case I just pass e from the method which contains this code snippet, how would I pass the timer's own EventArgs?

nawfal
  • 70,104
  • 56
  • 326
  • 368
Matt
  • 3,820
  • 16
  • 50
  • 73

2 Answers2

313

Timer.Elapsed expects method of specific signature (with arguments object and EventArgs). If you want to use your PlayMusicEvent method with additional argument evaluated during event registration, you can use lambda expression as an adapter:

myTimer.Elapsed += new ElapsedEventHandler((sender, e) => PlayMusicEvent(sender, e, musicNote));

Edit: you can also use shorter version:

myTimer.Elapsed += (sender, e) => PlayMusicEvent(sender, e, musicNote);
MagnatLU
  • 5,967
  • 1
  • 22
  • 17
  • 1
    Thanks it worked! I had to change the names of sender and e in the first set of brackets because they were the same as in the containing method. Could you please explain to me what they are? i.e. what's the difference between sender, e in the first bracket and the ones in the second? – Matt Dec 27 '11 at 11:57
  • 4
    `(sender, e) => PlayMusicEvent(sender, e, musicNote)` is anonymous method. Values in first brackets are actual parameter names and values in second brackets are actual parameters' usage. Think of it as short form for `void NONAME(var sender, var e) { PlayMusicEvent(sender, e, musicNote); }` where parameter names are inferred from context and `musicNote` is taken from local variables. This one line creates new method that uses your method and sets it as handler for timer's event. – MagnatLU Dec 27 '11 at 12:00
  • 21
    And how to remove this `eventHandler`? `-=` does not work. –  Mar 02 '13 at 14:59
  • 2
    @EruRōraito http://stackoverflow.com/questions/17995339/detach-event-handler-after-attaching-method-with-passed-parameter?noredirect=1#comment26312041_17995339 – TruthOf42 Aug 01 '13 at 13:42
  • "**evaluated during event registration**". Does this mean that the method is called at registration time, or that the method parameters are stored for execution as they were passed at registration time? – kdbanman Aug 13 '15 at 22:35
  • 6
    It's impossible to unsubscribe (as Yassine Houssni mentioned) from anonymous method in this case. To unsubcribe, you need to store event handler object (ElapsedEventHandler) somewhere and unsubscribe from exactly that instance. – white.zaz Oct 06 '15 at 11:36
  • I have menu items generated within a for-loop, and I want the handling method to be passed the int which I use to iterate through my loop. However, the int always becomes equal to the amount of iterations the loop has had and is thus out of bounds for my intent. Rather than 0 for the first, 1 for the second element, it will just be, say, 5 if my loop is `(int i=0; i<5; i++)` ...what do I do? – Ben Philipp May 28 '16 at 23:48
  • I still can't unsubscribe that method. Can anyone give me an example? – GinCanhViet Aug 11 '21 at 06:41
  • I believe the event can be unsubscribed like so: `var event = new ElapsedEventHandler((sender, e) => PlayMusicEvent(sender, e, musicNote)); myTimer.Elapsed += event; myTimer.Elapsed -= event;` – kesse May 26 '23 at 12:44
4

If I understand your problem correctly, you are calling a method instead of passing it as a parameter. Try the following:

myTimer.Elapsed += PlayMusicEvent;

where

public void PlayMusicEvent(object sender, ElapsedEventArgs e)
{
    music.player.Stop();
    System.Timers.Timer myTimer = (System.Timers.Timer)sender;
    myTimer.Stop();
}

But you need to think about where to store your note.

Dmitry Polyanitsa
  • 1,083
  • 9
  • 18