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.
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:
- 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.
- 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.
- 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!