Adding a coroutine to an event?

Is it possible to add a coroutine to an event? I’m experimenting with events, and it seems like it would be extremely useful. However, I’ve got to run a coroutine for one of the functions that will be assigned to the event. Don’t know if I’m explaining this correctly so here’s some code:

Event declaration:

public delegate void BookSelectEventHandler();
public static event BookSelectEventHandler BookSelect;
public static void OnBookSelect()
{
    BookSelectEventHandler bookSelect = BookSelect;
    if (bookSelect != null)
        bookSelect();
}

Basically what I want to do (but not a solution):

BookSelect += StartCoroutine(RenderWholeBook);

My function:

IEnumerator RenderWholeBook()
    {
                    //snap
        yield return null;  //return next frame
                    //change text
        yield return null;  //return next frame
                    //snap next page
        yield return null;  //return next frame
                    //turn off
        yield break;
    }

Is this even a viable approach? Or should I just do the long work around of reference and call the function?

Also thought about this:

public delegate void BookSelectEventHandler();
public static event BookSelectEventHandler BookSelect;
public static void OnBookSelect()
{
    BookSelectEventHandler bookSelect = BookSelect;
    if (bookSelect != null)
        StartCoroutine(bookSelect());
}

But it doesn’t work either.

Surprising simple:

public delegate IEnumerator BookSelectEventHandler();
public static event BookSelectEventHandler BookSelect;
public void OnBookSelect()
{
    BookSelectEventHandler bookSelect = BookSelect;
    if (bookSelect != null)
        StartCoroutine(bookSelect());
}

And you can only add functions with the return type of IEnumerator:

  • Only the last event handler to be added will be called – Luiz

  • I only use one, so it works for me

And this is how you would add the function to the event:

BookSelect += RenderWholeBook;

Updated my answer. Everything works perfectly.

I’m not sure what your intentions are, but you can’t start a directly coroutine from a static method since StartCoroutine is a member method from MonoBehaviour. Another problem is that the event handlers must be a coroutine, so they must return IEnumerator.

public delegate IEnumerator BookSelectEventHandler();
public static event BookSelectEventHandler BookSelect;
public void OnBookSelect()
{
    if (BookSelect != null)
        StartCoroutine(BookSelect());
}

static IEnumerator RenderWholeBook()
{
                //snap
    yield return null;  //return next frame
                //change text
    yield return null;  //return next frame
                //snap next page
    yield return null;  //return next frame
                //turn off
    yield break;
}

(...)

BookSelect += RenderWholeBook;

However there’s a problem: only the last handler is called.

I know it’s few years since question was asked but I had similiar problem.

My solution was to simply invoke every delegate manually.

public delegate IEnumerator PlannedActionsEventHandler();

private PlannedActionsEventHandler _plannedActions;

public void RegisterAction(PlannedActionsEventHandler plannedAction)
{
    _plannedActions += plannedAction;
}

private IEnumerator InvokeActions()
{
    if (_plannedActions != null)
    {
        //Invokes all planned actions and waits until they're done.
        foreach (var @delegate in _plannedActions.GetInvocationList())
        {
            yield return @delegate.DynamicInvoke();
        }
    }
}

Please let me know if they’re any problems with this method.

Your delegate needs to return an IEnumerator, as well as BookSelect's function, which is probably assigned from elsewhere. Then, you call StartCoroutine(bookSelect());

You can get past this with one more level of functionality.I actually hit the same problem
//delegate
public delegate void BookSelectEventHandler();
//event
public event BookSelectEventHandler BookSelect;
//Trigger Event Function
public void OnBookSelect()
{
if (BookSelect != null)
BookSelect();
}

//The function we want to run as a coroutine
IEnumerator RenderWholeBook()
    {
    //snap
    yield return null; //return next frame
    //change text
    yield return null; //return next frame
    //snap next page
    yield return null; //return next frame
    //turn off
    yield break;
    }
//Helper function that gets registered on the event and //calls the actual function we want to run as a coroutine //without waiting for it.
public void HelperFunction(){
    StartCoroutine(RenderWholeBook);
}
    (...)
//In a Start/Awake/OnEnable/WhateverEventRegistering code //you use
    BookSelect += HelperFunction;

This way when you register listeners to the BookSelect event they won’t be IEnumerators and won’t stumble on the restriction of just using the last listener/handler whatever you want to call it.

The problem is when you want to wait for the coroutine to finish…if you do then you can’t use a helper function because you’d need to yield return the RenderWholeBook which means you have to declare whatever function is going to call the “yield return …” piece of code.Which is kind of a chain reaction towards the parent function.
Calling StartCoroutine creates the coroutine and exits.Which means that if you need info about this you have to pass them through arguments.

Can’t you just make the event a void instead? You then use that void event to call your IEnumerator.
Also, note that on events you should likely be stopping your last IEnumerator!

 public delegate void BookSelectEventHandler();
 public static event BookSelectEventHandler BookSelect;
 public static void OnBookSelect()
{
     if (BookSelect != null)
        BookSelect();
}

Start()
{
    BookSelect += MyBookSelectHandler;
}

IEnumerator lastEnumerator = null;
public void MyBookSelectHandler()
{
    if (lastEnumerator != null)
        StopCoroutine(lastEnumerator);
    lastEnumerator =RenderWholeBook();
    StartCoroutine(lastEnumerator);
}



 IEnumerator RenderWholeBook()
 {
                 //snap
     yield return null;  //return next frame
                //change text
     yield return null;  //return next frame
               //snap next page
     yield return null;  //return next frame
               //turn off
     yield break;
 }