Update on ViewModel to ViewModel Navigation in Xamarin.Forms using MessagingCenter

If you're trying to do this as per my previous post here GHOST_URL/post/2014/07/26/using-messageingcenter-in-xamarin-forms-for-viewmodel-to-viewmodel-navigation.aspx and are getting this error:

*System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
*
...then you may be tripping over this:

https://bugzilla.xamarin.com/show_bug.cgiand ?id=22228)

(Xamarin.Forms v1.3.2.6316)

It seems to occur when you send a message, a subscriber picks up the message, and either subscribes or unsubscribes to/from the message is its handler. There’s a bit more info, as well as a solution to replicate the issue, in bugzilla if you follow the link above.

The workaround suggest by jruskin does the trick, although I did have to vary it a little. The solution is to put the following into the handler:

await System.Threading.Tasks.Task.Delay(25);

When this line is hit the await will relinquish control to the previous thread, meaning that the internals of the MessagingCenter can finish tidying up (or at least I’m assuming that’s the explanation J ). You’ll see that I’ve waited for 25 milliseconds, as opposed to the 1ms mentioned in the comment on Bugzilla. I’m testing on an HTC Desire, which required a 25ms pause to get rid of the exception.

Here’s an example:

private void SubscribeToMessages()
{
    MessagingCenter.Subscribe<Messages.NavigationMessage>(this, "Navigation", async (navigationMessage) =>
    {
        // Workaround for bug: https://bugzilla.xamarin.com/show_bug.cgi?id=22228
         // Await a small delay to give up the thread to the caller to finish enumeration of the sender list

        await System.Threading.Tasks.Task.Delay(25);
        switch (navigationMessage.Type)
        {
            case eNavigationType.ShowOneView:
                 Navigation.PushAsync(oneView, true);
                 break;
             case eNavigationType.ShowAnotherView:
                 Navigation.PushAsync(anotherView, true);
                 break;
             case eNavigationType.Back:
                 Navigation.PopAsync(true);
                 break;
             default:
                 break;
        }
    });
}