Move Button OnClick listeners to another button

What I want to achieve:
Create a component (MonoBehaviour) (which requires Button component on the same object) that will show confirmation dialog (“Do you really want to blah blah blah?” “Yes”/“No”) on button click. If “Yes” button is pressed, it does whatever the original Button should have done. If “No” - nothing.

The problem:
I can’t find any examples on moving event handlers from one button to another. I’m not very experienced with all those delegates, UnityActions and stuff… Googling failed. Documentation is… umm… scarce.

My component should grab original OnClick handlers and stuff them into its “Yes” button. After that it should replace original OnClick with its own handler that shows the confirmation dialog.
Replacing one handler with another is clear. The real problem is moving arbitrary handlers to another button.

So, how can I do these shenanigans?


I want to have an easily reusable component which I can just drop onto button and it works. I remove it and nothing breaks. I don’t want to fiddle around with “rewiring” event handlers manually. It seems like something that component can do for itself.

Also, I am using data binding library and the action that button executes is set by another component, so I don’t have direct control over the handler.

My fallback plan is to extend component that binds an action to have in-built functionality to show confirmation dialog, but I really want to avoid that. I want decoupled (as much as possible) functional components.

If moving arbitrary event handlers from one button to another is impossible, I will stick to my fallback plan.

I have achieved the desired behavior! Woohoo!

ThisButton - original button component

YesButton, NoButton - buttons in the confirmation dialog

            YesButton.onClick = ThisButton.onClick;

            ThisButton.onClick = new Button.ButtonClickedEvent(); // <-- IMPORTANT

The trick is to NOT use ThisButton.onClick.RemoveAllListeners(), because it would clear all the listeners on YesButton too (they share the same onClick instance).
Instead I just replace onClick instance of the original button with a new object.

Why not have 2 prefabs, one for your first screen and one for the next, so you instantiate one and delete the other, no need to “update” handlers.

In any case if you really want to point to new handlers you have another option, same handler with a click count, so you could know if it clicked the button for first time or second time and reset.

If still you need to replace the see AddListener and RemoveListener and if you want a little hing (also note how to capture a value there) 4.6 UI How to apply OnClick handler for button generated at runtime (script)? - Unity Answers

There are a few ways of doing something like this although I don’t think you want to necessarily ‘take’ the handlers from the original buttons and move them over so much as have the original buttons assign the right function to any given Yes button. You could do that by storing the function you want to run with the next pressed Yes button into a delegate, basically a variable that holds a function, and then adding that delegate as the listener of the Yes button when it is Instantiated. It would look something like this:

private GameObject buttonCanvas;
private GameObject confirmCanvResource;
//Separate the reference to the prefab and the GO you destroy
private GameObject confirmationCanvas;

//Create a delegate of a custom type to hold the function called by the next 'Yes' click
private delegate void Handler();
private Handler currentHandler;

void Start()
    buttonCanvas = GameObject.Find("ButtonCanvas");
    confirmCanvResource = Resources.Load("ConfirmationCanvas") as GameObject;

//Called by the buttons preceding Yes/No to set the Yes button with the right handler
public void OnButtonClick()
    currentHandler = IntendedFunction;
    confirmationCanvas = Instantiate(confirmCanvResource);
    Button[] buttons = confirmationCanvas.GetComponentsInChildren<Button>();
    for (int i = 0; i < buttons.Length; i++)
        if (buttons*.name == "Yes")*

buttons*.onClick.AddListener(delegate { currentHandler(); });*
//You’ll also need to add logic for your other buttons
public void IntendedFunction()
//Do stuff after ‘Yes’ is clicked
There’s a few details here worth mentioning, like creating multiple GameObjects for the confirmation canvas. If you were to create just one reference to the Resource then when you went to Destroy it you would be trying to destroy the prefab itself rather than an instance of it. The delegate is defined, you can think of it like defining a function with no contents except by putting the delegate keyword in there you’re creating a type (like int or string) instead of an actual function. Then after that you create an instance of that delegate type named currentHandler that stores the function that will get called on the next Yes button click. Finally, when one of the normal buttons is clicked it destroys it’s canvas, instantiates the Yes/No canvas, and adds the delegate handler to the Yes button.