How to stop InputListener events from persisting after screen change?

I have successfully implemented Input Listeners but the event handlers are still hooked up after I change the screen.
My Menu screen has 5 buttons that are hooked up on mouse click. In the button event handler I check the mouse position to determine which button was clicked. Then I change screens. The event handlers still persist on the new screen so when a button is clicked on the new screen that overlaps the button on the previous screen both are fired.
Is there a way to unhook all the listeners at once when changing screens? To date I have only implemented the Input Listeners in my buttons. I have many controls and sprites where I could use this.
Hope somebody can help.

https://msdn.microsoft.com/en-us/library/ms366768.aspx

Thank you for the reply. But this does not solve the problem. There are 5 buttons on my menu screen each subscribed.
My screens are not components. They are in a list in my Screen Manager. When I switch screens, I delete the menu screen and replace it with another screen but monogame still keeps the hookup of the eventhandlers of the 5 buttons. I have to find a way to unhook the handlers of the 5 buttons. I was hoping there was a way to unhook all the listeners at once.

maybe post some code then, usually you hook with

EventAction += Event;

and unhook with

EventAction -= Event;

I tried to unsubscribe the Listeners but they did not seem to unsubscribe so I set up a little test:
I subscribed and then immediately unsubscribed.
mouseListener.MouseMoved += (sender, args) => MouseMoved(sender, args);
mouseListener.MouseMoved -= MouseMoved;
the listener remained subscribed. Apparently, all the buttons remained subscribed and when I changed screens all the subscriptions remained.
How can I change the InputListener to unsubscribe event handlers?
Thanks.

Hmm. To be honest, this sounds like a bit of a mess…

So, just to make sure I’ve understood it correctly, each button has its own Clicked event handler, in which you’ve implemented MouseInputListener which listens to the mouse input, triggering if the cursor is inside the area of the button?

Let me explain what I’m trying to do.
I have a tree of controls screens, forms, buttons, textboxes etc. The top of the tree is the screen manager. All the controls are based on Control. The screen manager is a drawable component that updates and draws all the controls in the tree. I had all the input (a component) in the update method of each control checking to see if that control had focus. Everything, worked well. Now, I wanted to modify the tree dynamically. Create controls on the fly. Example create and add items to a list box. This all works well except that in the game loop the input check registers true on each cycle causing methods to be executed more that once.i.e. loading items in a listbox or changing the function of a button.
I thought that if I converted the input to Input Listeners, I would be able to rely on each input event only firing once and avoiding the duplication.
So in each control I access the input listener and subscribe to the input event. In the event handler I determine which control the event was from and do the action. This works fine except that the I can’t turn off the subscription when the tree changes i.e. screen changes or form changes.
Hope this helps to understand what I am doing.

It’s really unclear what’s going on here.

If it turns out to be a bug in Extended, we’ll definitely fix it but at this stage it’s likely a problem with your code.

My suggestion is to post the code, a description of what you’re expecting to happen and what’s actually happening. Hopefully we can get to a minimal working example and help to fix it.

Even if the problem is with your code rather than a bug in the library, we’ll still do whatever we can to help. Unfortunately the description given so far is quite abstract and it’s difficult to know what’s going on.

I’m not trying to be mean, sorry if it’s coming across that way. I realize these kinds of bugs can be quite frustrating and I know it’s difficult to communicate what’s going on when you don’t understand it yourself. I’m just not how to reproduce the bug you’re experiencing.

Thanks for the response. Simply put, I am trying to dynamically change the elements of my game.

Basically, I am not sure how event handling works in monogame so I tried to switch from polling input to event driven input. The input listeners all worked well except I was unable to unsubscribe a mouse event.
I added this line

mouseListener.MouseClicked -= (sender, args) => LogMessage("{0} mouse button clicked", args.Button);

in the initialize method of the demo but it did not unsubscribe the event…

Is this the right way to unsubscribe a mouselistener event?

This is the first step in understanding eventhandling in monogame. I would like to understand the life cycle of the event handling. i.e. when an object is removed from a list are the subscribed eventhandlers deleted. When a button is clicked can the eventhandler unsubscribe that event and subscribe to another. Changing the gamestate handling dynamically gets pretty complicated.

Ok. Now it makes sense…

Hi, I’m Psilo.

Basically the thing you try to do isn’t possible since, when you create a delegate using a lambda expression, chances are that the delegates are not equal (they are two objects, distinct from one another). When you unsubscribe the second one, it’s checked if the event contains the handler by using the object reference (equals) and it isn’t. So it’s not unsubscribed.

You’re basically doing:

mouseListener.MouseClicked += a;
...
mouseListener.MouseClicked -= b;

Here are the details about that and a short workaround from the almighty Skeet.

Hello throbax,
Actually in my code I don’t use lambda expressions.

Could I add a mouseListener.MouseClicked without a lambda expression or do I have to use the same delegate definition as in the mouselistener itself. Or change the mouse listener code.

The work around is very messy. Why use lambda expressions just to save a bit of coding?

Very old school guy.

mouserListener.MouseClicked += OnMouseClicked;
...
mouserListener.MouseClicked -= OnMouseClicked;
...
private void OnMouseClicked(object sender, MouseEventArgs args)
{
    ...
}

In C# the observer pattern is baked into the language in the forms of delegates / events. The += for an event is just adding a delegate (in this case OnMouseClicked) to a list of delegates that are be invoked when the event is fired (the order of the delegates that are invoked is unimportant). Similiarly -= for an event is removing the delegate from the list. Thus, in order to unsubscribe, the same delegate that was added using += has to be removed using -=.

Then why are you using them here in your examples all of the time?

This won’t work since the right half of the += call is a lambda expression returning a new delegate to MouseMoved(sender, args) and in the next line you unsubscribe MouseMove(sender, args), not the delegate you created earlier on.

Here again:

Again. You’re generating an anonymous delegate to the LogMessage method… Again not the one you probably subscribed, so the unsubscribe call will do nothing at all.

You asked:

And I answered that, no, it is not, because you’re not unsubscribing the same delegate as you were subscribing.

The link I provided lists all possible method of subscribing and unsubscribing an event (in general).
Without any lambdas (I prefer not to use those as well):

// Code provided by Jon Skeet...
public void ShowWoho(object sender, EventArgs e)
{
     MessageBox.Show("Woho");
}
...
button.Click += ShowWoho;
...
button.Click -= ShowWoho;

If you say your code looks different, that please provide some. It would be a lot easier to see what we’re actually talking about…
And we’d really like to help.

The reason I was using lambda expressions is that the demo provided by MonoGame.Extended.InputListeners used them.
I changed my code from
mouseListener.MouseClicked += (sender, args) => ButtonClicked(sender, args);
to
mouseListener.MouseClicked += ButtonClicked;
and was able to unsubscribe using
mouseListener.MouseClicked -= ButtonClicked;

Thanks for the education!!:slight_smile:

Now is there a way to find out the subscribers and unhook them from an object event.
I’m trying to traverse through a tree of controls and want to create a back button and need to unhook the previous eventhandler but don’t know the signature.

Hope this is not too confusing.

Ok.
The next thing is: An object subscribing to an event, because it wants to consume it, is responsible for unsubscribing from that event.
You could make a method encapsulating all unsubscribe-calls, corresponding to the subscribe-calls you do when allocating that control, and call it before removing that control.

Update:
One thing you could do, although it’s considered extremely bad practice, would be:

/// <summary>
///     This method checks if a specific eventHandler is already registered on an event by
///     use of reflection.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="handler">The handler.</param>
/// <param name="handlerMethodName">The name of the eventHandler to check if it is present on that event.</param>
/// <returns>
///     True, if the handler is already registered on that event. Otherwise <c>false</c>.
/// </returns>
public static bool IsInInvocationList<T>(this EventHandler<T> handler, string handlerMethodName) where T : EventArgs
{
	bool isFound = false;
	foreach (Delegate myDelegate in handler.GetInvocationList())
	{
		if (myDelegate.Method.Name.Equals(handlerMethodName))
		{
			isFound = true;
			break;
		}
	}
	return isFound;
}

// <summary>
///     This method checks if a specific eventHandler is already registered on an event by
///     use of reflection.
/// </summary>
/// <param name="handler">The handler.</param>
/// <param name="handlerMethodName">The name of the eventHandler to check if it is present on that event.</param>
/// <returns>
///     True, if the handler is already registered on that event. Otherwise <c>false</c>.
/// </returns>
public static bool IsInInvocationList(this EventHandler handler, string handlerMethodName)
{
	bool isFound = false;
	foreach (Delegate myDelegate in handler.GetInvocationList())
	{
		if (myDelegate.Method.Name.Equals(handlerMethodName))
		{
			isFound = true;
			break;
		}
	}
	return isFound;
}

And it’s slow, so to anyone reading this by chance: Don’t do that!