Thomas Bandt

A Nicer Messaging Interface For Xamarin.Forms

Xamarin.Forms provides cross-platform messaging capabilities for Android, iOS and Windows Phone with its MessagingCenter – but in a really strange fashion. I thought there must be a simpler way.

Published on Monday, 18 January 2016

A Good One: MvvmCross Messenger Plugin

Working with the MvvmCross Messenger Plugin for a while now, I got used to the idea of just sending simple message objects that I can define myself.

All you need to do with that MvvmCross messenger is to create a new message type, derive it from MvxMessage and publish it.

The interface for sending is that simple. And even subscribing to messages of a certain types is that simple as well – you define the type of the message you want to listen to, a callback which gets a parameter of that message type, and you're basically done. Read more about it here.

The Odd One: Xamarin.Forms MessagingCenter

If you're now taking a look at the MessagingCenter of Xamarin.Forms, some things appear to be a bit odd:

  1. When sending a message, you always must provide the sender. I don't know many cases from my very own experience where the sender is needed anyway.
  2. What's called message here, is just a magic string. Everyone who's dealing with that "message" needs to know it. You better add a central class with some constants, when possible.
  3. When subscribing to a message, you also have to know the sender. See my first point – if you almost never need the sender, what's the point in being forced to know it as a subscriber? That doesn't make sense to me, and at least it's making decoupling parts of the application harder than it needs to be.

IMessenger – MessagingCenter Improved

I thought especially independence of sender and subscriber should be a goal worth doing some extra work. And here it is:

public interface IMessage
{
}

public interface IMessenger
{
    void Send<TMessage>(TMessage message, object sender = null)
        where TMessage : IMessage;

    void Subscribe<TMessage>(object subscriber, Action<object, TMessage> callback)
        where TMessage : IMessage;

    void Unsubscribe<TMessage>(object subscriber)
        where TMessage : IMessage;
}

public class FormsMessenger : IMessenger
{
    public void Send<TMessage>(TMessage message, object sender = null) where TMessage : IMessage
    {
        if (sender == null)
            sender = new object();

        MessagingCenter.Send<object, TMessage>(sender, typeof(TMessage).FullName, message);
    }

    public void Subscribe<TMessage>(object subscriber, Action<object, TMessage> callback) where TMessage : IMessage
    {
        MessagingCenter.Subscribe<object, TMessage>(subscriber, typeof(TMessage).FullName, callback, null);
    }

    public void Unsubscribe<TMessage>(object subscriber) where TMessage : IMessage
    {
        MessagingCenter.Unsubscribe<object, TMessage>(subscriber, typeof(TMessage).FullName);
    }
}

Usage now is very straight-forward.

1. Define Your Message

public class AlbumCreatedMessage : IMessage
{
    public readonly Album Album;

    public AlbumCreatedMessage(Album album)
    {
        Album = album;
    }
}

2. Send It Around

var album = new Album
{
    Id = Guid.NewGuid(),
    Title = "Hello World"
};

// An instance of IMessenger
Messenger.Send(new AlbumCreatedMessage(album));

3. Subscribe To It

// An instance of IMessenger
Messenger.Subscribe<AlbumCreatedMessage>(this, AlbumAdded);

private void AlbumAdded(object sender, AlbumCreatedMessage message)
{
    // Do something
}

4. When You're Done, Unsubscribe

Messenger.Unsubscribe<AlbumCreatedMessage>(this);

I think that's a clean way to send and receive messages.

What do you think? Drop me a line and let me know!