Automagical Messenger registration

Aug 16, 2011 at 8:34 PM

 

 /// 
    ///  Used with MessengerHelper to Auto-magically registers all methods with the MvvMLight Messenger.
    /// 
    /// 
    /// [MessengerMethod]
    /// publiv void OnMyMessage(MyMessage args){
    /// }
    /// 
    [AttributeUsage(AttributeTargets.Method)]
    public class MessengerMethodAttribute : Attribute {

        public object Token { get; set; }

        public bool ReceiveDerivedMessagesToo { get; set; }
    }

    public static class MessengerHelper {

        /// 
        /// Auto-magically registers all methods decorated with the MessengerMethodAttribute with the MvvMLight Messenger.
        ///  
        /// 
        /// public class MyModal {
        ///     void MyModal() {
        ///         NessengerHelper.Register(this);
        ///     }
        /// 
        ///     [MessengerMethod]
        ///     publiv void OnMyMessage(MyMessage args) {
        ///     }
        /// }
        /// 
        /// <param name="instance" />The instance with the methods to register
        public static void Register(object instance)
        {
            // the view modal
            var type = instance.GetType();

            //loop through each method, possibly registering with the messenger
            foreach (var method in type.GetMethods())
            {
                //get the attribute
                var info =
                     Attribute.GetCustomAttribute(method,
                     typeof(MessengerMethodAttribute),
                     true) as MessengerMethodAttribute;

                //no MessengerMethod attribute ? ignore
                if (info == null)
                    continue;

                //get input paramaters (the type to register for)
                var paramaters = method.GetParameters();

                if (paramaters.Count() != 1)
                    throw new Exception("MessengerMethods must have exactly 1 input paramater.");

                //create the Action delegate to pass into the messenger
                var paramaterType = paramaters.Single().ParameterType;
                var delgateType = Expression.GetActionType(new[] { paramaterType });
                var delgate = Delegate.CreateDelegate(delgateType, instance, method);

                //create the Registration paramater array
                var registerParamaters = new[]
                                            {
                                                instance,
                                                info.Token,
                                                info.ReceiveDerivedMessagesToo,
                                                delgate
                                            };

                // register with Messenger via Reflection
                var registerMethod = Messenger.Default
                        .GetType()
                        .GetMethods()
                    // note potential bug if they ever change the name of the Register method
                        .Where(o => o.Name == "Register")
                    // note potential bug if they ever change the order
                    // should find a better way to discover correct method overload
                        .Last()
                        .MakeGenericMethod(new[] { paramaterType });

                registerMethod.Invoke(Messenger.Default, registerParamaters);
            }

        }


    }