New Mediator

436 views
Skip to first unread message

Marlon Grech

unread,
Apr 6, 2009, 3:56:14 PM4/6/09
to wpf-di...@googlegroups.com
Hi all,

Today I had a few minutes to think about the "Memory Leak" in the Mediator implementation I did. I implemented a new version that solves this issue. I am not 100% happy since my solution uses Reflection (yes I love reflection and end up fitting it everywhere).

Basically the memory leak is solved by using a WeakReference and then using reflection to call a method on the WeakRefernce Target. This way GC can collect the ViewModel when it is not being used any more and the Mediator can check if the ViewModel is alive or not (and if not remove it from the InvocationList)

here is the WeakDelegate (Josh suggested this name I was gonna go for something crazy such as WeakCollogueInvoker :) lol haha)

class WeakDelegate : WeakReference
        {
            public string Method { get; private set; }

            private MethodInfo methodInfo;

            public WeakDelegate(object target, string method)
                : base(target)
            {
                Method = method;
                methodInfo = Target.GetType().GetMethod(Method, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
                if (methodInfo == null)
                    throw new InvalidOperationException(String.Format("Method {0} was not found on target object", Method));
            }

            public void Notify(object args)
            {
                if (IsAlive)
                    methodInfo.Invoke(Target, new[] { args });
            }
        }

... and here is how the Mediator does the invocation / cleanup

if (invocationList.ContainsKey(message))
            {
                for (int i = 0; i < invocationList[message].Count; i++)
                {
                    var weakDelegate = invocationList[message][i];
                    if (weakDelegate.IsAlive)
                        weakDelegate.Notify(args);
                    else//remove the weak delegate from the invokation list
                    {
                        invocationList[message].RemoveAt(i);
                        i--;
                    }
                }
            }

... in Order to Register for a message from a VM you do the following

Mediator.Instance.Register(MediatorMessages.Message1, this, "Test");

anyway I attached a project that demos this... have a look and tell me what you think..... once we agree on this I will publish this as an update to my article....

P.S I am using strings not an enum. I do this becuase strings can be defined in other projects then the Mediator project.... I see a Mediator as a chat room.... A chat room does not know what messages are passing... the people chatting define those.... Mediator for me is similar


Regards
Marlon
WPF Blog - http://marlongrech.wordpress.com/

Marlon Grech

unread,
Apr 6, 2009, 3:58:06 PM4/6/09
to wpf-di...@googlegroups.com
oops... forgot to attach the file :D

hihi :D


Regards
Marlon
WPF Blog - http://marlongrech.wordpress.com/



MediatorTest.zip.rename2

Josh Smith

unread,
Apr 6, 2009, 3:59:44 PM4/6/09
to wpf-di...@googlegroups.com
I don't think you should include the 'Static' binding flag.  The callbacks will always be instance methods on the Target object, no?

Marlon Grech

unread,
Apr 6, 2009, 4:00:29 PM4/6/09
to wpf-di...@googlegroups.com
and yes I know this would blow up in a PartialTrust CAS.....


Regards
Marlon
WPF Blog - http://marlongrech.wordpress.com/



On Mon, Apr 6, 2009 at 9:56 PM, Marlon Grech <marlo...@gmail.com> wrote:

Marlon Grech

unread,
Apr 6, 2009, 4:01:49 PM4/6/09
to wpf-di...@googlegroups.com
I did that jsut in case someone wants to define a method like this

public static void Test(object test)
        {
            MessageBox.Show("Message from mediator");
        }

otherwise reflection would not get that method...


Regards
Marlon
WPF Blog - http://marlongrech.wordpress.com/



Josh Smith

unread,
Apr 6, 2009, 4:35:35 PM4/6/09
to wpf-di...@googlegroups.com
I think it would be better to decorate the callback methods of the Colleagues with an attribute, and specify the message ID in the attribute's constructor.  In your Mediator/WeakDelegate code, scan the Target object (i.e. Colleague) for a method decorated with your custom attribute, where the MessageID equals the message of interest.  This is better than passing in the method name to the Mediator for the following reasons:

1) The method names on the Colleagues classes are not duplicated in the code.  If you change the name of the callback, you don't have to remember to change the method name passed to the Mediator.

2) The Colleague class's are more self-documenting, because the callback methods are attributed with the Message ID that they are associated with.

3) The callback locating logic is simplified, because you don't have to worry about things like method overloads.

What do you think?

Josh

Marlon Grech

unread,
Apr 6, 2009, 4:45:47 PM4/6/09
to wpf-di...@googlegroups.com
I like this....

I would do it a bit different.... (or the same as you are saying which would mean I didn't understand correctly, which is most likely the case here :) )


something like this


class MyVM
{
    [MediatorNotification(MediatorMessages.Message1]
    public void Test(object args )
    {
       ....
    }
   
    public MyVM()
   {
              Mediator.Register(this);
   }
}

the register would scan the VM and register all the methods to the messages. This way you only scan once.... what do you think? I think we are saying the same thing



Regards
Marlon
WPF Blog - http://marlongrech.wordpress.com/



Mike Brown

unread,
Apr 6, 2009, 4:49:13 PM4/6/09
to wpf-di...@googlegroups.com
I think that's a brilliant idea Josh...however, how would the registration occur? Another alternative would be to use that static reflection trick that I posted for INPC

Mike Brown

unread,
Apr 6, 2009, 4:50:29 PM4/6/09
to wpf-di...@googlegroups.com
Remember you can't use a parameter to an Attribute unless it's a compile time constant or an enum.

Josh Smith

unread,
Apr 6, 2009, 4:50:54 PM4/6/09
to wpf-di...@googlegroups.com
I'm not sure.  I might want to register/unregister for certain messages at certain times. Then again, I could put logic into my callbacks that aborts if i don't want to act on some message at the time.  Hmm...

Josh Smith

unread,
Apr 6, 2009, 4:51:47 PM4/6/09
to wpf-di...@googlegroups.com
In Marlon's setup, the message IDs can be const strings exposed off some class.  That should work ok.

Marlon Grech

unread,
Apr 6, 2009, 4:53:59 PM4/6/09
to wpf-di...@googlegroups.com
hehe... I already have the code in my mind.... all I need is 5 minutes to write it :P haha....

but let's wait for the other Disciples to put their input....

P.S And yes mike it is do able.... I already did this in a sample app with a similar setup.... in the example I wrote the parameter is a constant which is the way you should define a Mediator message.


Regards
Marlon
WPF Blog - http://marlongrech.wordpress.com/



Marlon Grech

unread,
Apr 6, 2009, 5:16:28 PM4/6/09
to wpf-di...@googlegroups.com
couldn't help it... otherwise would not sleep...

here is the new Register method

public void Register(object target)
        {
            foreach (var methodInfo in target.GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static))
                foreach (RegisterMediatorMessageAttribute attribute in methodInfo.GetCustomAttributes(typeof(RegisterMediatorMessageAttribute), true))
                    invocationList.AddValue(attribute.Message, new WeakDelegate(target, methodInfo.Name));
        }

... The Attribute

[AttributeUsage(AttributeTargets.Method)]
    public class RegisterMediatorMessageAttribute : Attribute
    {
        public string Message { get; set; }

        public RegisterMediatorMessageAttribute(string message)
        {
            Message = message;
        }
    }

... and now the cool part

How the VM uses this
class ColleagueA {
        public ColleagueA()
        {
            Mediator.Instance.Register(this);
        }

        [RegisterMediatorMessage(MediatorMessages.Message1)]

        public static void Test(object test)
        {
            MessageBox.Show("Message from mediator");
        }

What do you think guys?

P.S in a real world application this  Mediator.Instance.Register(this); will not be in every VM because it would be in the BaseViewModel (or at least i would put it there so that you don't have to call it every time)


Regards
Marlon
WPF Blog - http://marlongrech.wordpress.com/



Mike Brown

unread,
Apr 6, 2009, 5:28:52 PM4/6/09
to wpf-di...@googlegroups.com
I wonder if that would scale out to where the Mediator would be some kind of service on another machine. That would work well in that scenario Udi Dahan talked about in this month's MSDN.

Marlon Grech

unread,
Apr 6, 2009, 5:32:19 PM4/6/09
to wpf-di...@googlegroups.com
Why would you want the Mediator as a service on another machine? I don't think this needs that kind of scalability


Regards
Marlon
WPF Blog - http://marlongrech.wordpress.com/



Mike Brown

unread,
Apr 6, 2009, 6:42:54 PM4/6/09
to wpf-di...@googlegroups.com
Look at the article I linked to. That's a perfect example of how a distributed mediator would be a good thing.

Josh Smith

unread,
Apr 7, 2009, 12:17:32 AM4/7/09
to wpf-di...@googlegroups.com
Hey all,

I set aside some time tonight to work on the Mediator problem.  I refined Marlon's awesome solution, and removed the need for using reflection to locate the target method.  I posted an entry on my blog, showing the prototype, and asked for suggestions/improvements/bugs/etc.  If I get any good feedback on it, I'll send them your way.

Here's the blog post:

http://joshsmithonwpf.wordpress.com/2009/04/06/a-mediator-prototype-for-wpf-apps/

Josh

Sacha Barber

unread,
Apr 7, 2009, 3:41:27 AM4/7/09
to wpf-di...@googlegroups.com
Marlon

I like Joshes idea of attributes, let us know when we have some new code to look at.


Date: Mon, 6 Apr 2009 18:42:54 -0400
Subject: [WPF Disciples] Re: New Mediator
From: mbro...@gmail.com
To: wpf-di...@googlegroups.com

Get the New Internet Explore 8 Optimised for MSN. Download Now

Marlon Grech

unread,
Apr 7, 2009, 3:44:56 AM4/7/09
to wpf-di...@googlegroups.com
I posted the code yesterday.... here let me attach it again

here is the new Register method

public void Register(object target)
        {
            foreach (var methodInfo in target.GetType().GetMethods(
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static))
                foreach (RegisterMediatorMessageAttribute attribute in methodInfo.GetCustomAttributes(typeof(RegisterMediatorMessageAttribute), true))
                    invocationList.AddValue(attribute.Message, new WeakDelegate(target, methodInfo.Name));
        }

... The Attribute

[AttributeUsage(AttributeTargets.Method)]
    public class RegisterMediatorMessageAttribute : Attribute
    {
        public string Message { get; set; }

        public RegisterMediatorMessageAttribute(string message)
        {
            Message = message;
        }
    }

... and now the cool part

How the VM uses this
class ColleagueA {
        public ColleagueA()
        {
            Mediator.Instance.Register(this);
        }

        [RegisterMediatorMessage(MediatorMessages.Message1)]

        public static void Test(object test)
        {
            MessageBox.Show("Message from mediator");
        }


Regards
Marlon
WPF Blog - http://marlongrech.wordpress.com/



MediatorTest.zip.rename2

Marlon Grech

unread,
Apr 7, 2009, 3:46:16 AM4/7/09
to wpf-di...@googlegroups.com
Josh,

Maybe I am missing something but your solution still would blow up in Partial trust... Delegate.CreateDelegate is still reflection at the end of the day no? (It still has CAS for ReflectionPermission)


Regards
Marlon
WPF Blog - http://marlongrech.wordpress.com/



Laurent Bugnion, GalaSoft [MVP, MCP]

unread,
Apr 7, 2009, 5:05:26 AM4/7/09
to wpf-di...@googlegroups.com

Hey Josh,

 

I just commented on your blog with 2 questions. Would love if you can reply there. In the mean time I will try that myself, thanks!!

 

Laurent

 

From: wpf-di...@googlegroups.com [mailto:wpf-di...@googlegroups.com] On Behalf Of Josh Smith
Sent: Tuesday, April 07, 2009 6:18 AM
To: wpf-di...@googlegroups.com
Subject: [WPF Disciples] Re: New Mediator

 

Hey all,

No virus found in this incoming message.
Checked by AVG - www.avg.com
Version: 8.0.238 / Virus Database: 270.11.43/2043 - Release Date: 04/06/09 06:22:00

Laurent Bugnion, GalaSoft [MVP, MCP]

unread,
Apr 7, 2009, 5:31:49 AM4/7/09
to wpf-di...@googlegroups.com

Just curious, did any of you guys try NInject or another Dependency Injection framework to solve this kind of issues? I know I promised I would write about it, and didn’t have time yet, but with NInject you get a central repository of objects, which provides an easy access to them. For example, if you create a MainViewModel and a SecondaryViewModel using NInject, you can then easily get the SecondaryViewModel from the MainViewModel and call methods on it directly.

 

NInject adds a little overhead to the application (especially in Silverlight where size matters), but offers the advantage of a well known, well tested framework to solve this kind of issues. In addition, it is very easy to create a design time view model vs a runtime view model, and to keep the design time implementation separate.

 

Just curious to hear your thoughts, and yes I will write about it, I promise J

 

Laurent

Version: 8.0.238 / Virus Database: 270.11.43/2043 - Release Date: 04/06/09 18:59:00

Shawn Wildermuth

unread,
Apr 7, 2009, 5:49:08 AM4/7/09
to wpf-di...@googlegroups.com

I am currently writing a MSDN article on Prism (which uses Unity’s DI container, but you could use Ninject or other container) and it solves this issue with a typical IoC model but also for Silverlight allows you to specify modules in .xap files that can be downloaded behind the scenes or on demand.  Prism encompasses other problems (I like the DelegateCommand<> and EventAggregator a lot too). In this way I think Prism solves a lot of problems for WPF, but the ondemand and componentization at the .xap level loading of silverlight projects make it a home run for Silverlight IMHO.

 

Thanks,

 

Shawn Wildermuth

http://wildermuth.com

https://agilitrain.com

Microsoft MVP (C#), MCSD.NET, Author and Speaker

 

The Silverlight Tour is coming to a city near you!

Laurent Bugnion, GalaSoft [MVP, MCP]

unread,
Apr 7, 2009, 6:20:35 AM4/7/09
to wpf-di...@googlegroups.com
Yes the solution I experimented with NInject worked like a charm for
Silverlight too.

-----Original Message-----
From: wpf-di...@googlegroups.com [mailto:wpf-di...@googlegroups.com]
On Behalf Of Shawn Wildermuth
Sent: Tuesday, April 07, 2009 11:49 AM
To: wpf-di...@googlegroups.com
Subject: [WPF Disciples] Re: New Mediator

I am currently writing a MSDN article on Prism (which uses Unity's DI
container, but you could use Ninject or other container) and it solves
this issue with a typical IoC model but also for Silverlight allows you
to specify modules in .xap files that can be downloaded behind the
scenes or on demand. Prism encompasses other problems (I like the
DelegateCommand<> and EventAggregator a lot too). In this way I think
Prism solves a lot of problems for WPF, but the ondemand and
componentization at the .xap level loading of silverlight projects make
it a home run for Silverlight IMHO.

Thanks,

Shawn Wildermuth

http://wildermuth.com <http://wildermuth.com/>

https://agilitrain.com <http://wildermuthconsulting.com/>

Microsoft MVP (C#), MCSD.NET, Author and Speaker

The Silverlight Tour <http://www.silverlight-tour.com/> is coming to a

Josh Smith

unread,
Apr 7, 2009, 8:11:05 AM4/7/09
to wpf-di...@googlegroups.com
Yeah, that's true, but it doesn't use MethodInfo.Invoke(), which is supposed to be slower than CreateDelegate + invoking a delegate (according to the info I saw on the Web, which isn't necessarily correct!).  I'm not too worried about the permissions thing, but the performance is something worth considering. 

Josh

Marlon Grech

unread,
Apr 7, 2009, 8:22:40 AM4/7/09
to wpf-di...@googlegroups.com
ow ok.... fair enough.... CreateDelegate is in fact better performance wise...

Regards
Marlon
WPF Blog - http://marlongrech.wordpress.com/



Josh Smith

unread,
Apr 7, 2009, 8:25:14 AM4/7/09
to wpf-di...@googlegroups.com
I'm still not convinced that I'm happy with this Mediator design.  The prototype I posted last night works, but I still think that the attribute-based design we'd discussed yesterday might be better.  Perhaps it might be good to allow for both message-by-message registration, and also wholesale registration for all of an object's message sinks.  What do you think?  What would you prefer?

Josh

Marlon Grech

unread,
Apr 7, 2009, 8:33:10 AM4/7/09
to wpf-di...@googlegroups.com
Yesterday I posted the code for the attributes... I think it cool... did you have time to look at it?

Regards
Marlon
WPF Blog - http://marlongrech.wordpress.com/



Sacha Barber

unread,
Apr 7, 2009, 8:35:35 AM4/7/09
to wpf-di...@googlegroups.com
I liked it.




Date: Tue, 7 Apr 2009 14:33:10 +0200

Subject: [WPF Disciples] Re: New Mediator

" Upgrade to Internet Explorer 8 Optimised for MSN. " Download Now

Josh Smith

unread,
Apr 7, 2009, 8:40:53 AM4/7/09
to wpf-di...@googlegroups.com
I saw it, and loved it!  Perhaps you might want to roll my WeakAction implementation (which is faster than the MethodInfo.Invoked() approach) into your attribute-based approach? 

Josh

Marlon Grech

unread,
Apr 7, 2009, 8:41:52 AM4/7/09
to wpf-di...@googlegroups.com
yea definitly :)

Cool will stitch the code together and publish it :D


Regards
Marlon
WPF Blog - http://marlongrech.wordpress.com/



Josh Smith

unread,
Apr 7, 2009, 8:43:40 AM4/7/09
to wpf-di...@googlegroups.com
As Karl/KDAWG/Keith mentioned to me yesterday, this is the real power of the Disciples.  The fact that passionate people all over the world can easily collaborate on projects like this is fantastic.  :)

Josh

Marlon Grech

unread,
Apr 7, 2009, 8:50:57 AM4/7/09
to wpf-di...@googlegroups.com
The Disciples ROCK :) yea yea :D


Regards
Marlon
WPF Blog - http://marlongrech.wordpress.com/



Sacha Barber

unread,
Apr 7, 2009, 8:50:09 AM4/7/09
to wpf-di...@googlegroups.com
Yes I see bit from all of us in there.

GREAT


Date: Tue, 7 Apr 2009 08:43:40 -0400

Subject: [WPF Disciples] Re: New Mediator

Bill Kempf

unread,
Apr 7, 2009, 9:27:15 AM4/7/09