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
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
On Mon, Apr 6, 2009 at 9:56 PM, Marlon Grech <marlongr...@gmail.com> wrote: > 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
> 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
> On Mon, Apr 6, 2009 at 9:56 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>> 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
>> 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
On Mon, Apr 6, 2009 at 9:56 PM, Marlon Grech <marlongr...@gmail.com> wrote: > 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
> 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
On Mon, Apr 6, 2009 at 9:59 PM, Josh Smith <flappleja...@gmail.com> wrote: > I don't think you should include the 'Static' binding flag. The callbacks > will always be instance methods on the Target object, no?
> On Mon, Apr 6, 2009 at 3:58 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>> On Mon, Apr 6, 2009 at 9:56 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>>> 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
>>> 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
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.
On Mon, Apr 6, 2009 at 3:56 PM, Marlon Grech <marlongr...@gmail.com> wrote: > 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
> 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
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
On Mon, Apr 6, 2009 at 10:35 PM, Josh Smith <flappleja...@gmail.com> wrote: > 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
> On Mon, Apr 6, 2009 at 3:56 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>> 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
>> 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
On Mon, Apr 6, 2009 at 4:35 PM, Josh Smith <flappleja...@gmail.com> wrote: > 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
> On Mon, Apr 6, 2009 at 3:56 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>> 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
>> 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
On Mon, Apr 6, 2009 at 4:45 PM, Marlon Grech <marlongr...@gmail.com> wrote: > 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 ) > { > .... > }
> 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
> On Mon, Apr 6, 2009 at 10:35 PM, Josh Smith <flappleja...@gmail.com>wrote:
>> 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
>> On Mon, Apr 6, 2009 at 3:56 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>>> 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
>>> 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
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...
On Mon, Apr 6, 2009 at 4:45 PM, Marlon Grech <marlongr...@gmail.com> wrote: > 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 ) > { > .... > }
> 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
> On Mon, Apr 6, 2009 at 10:35 PM, Josh Smith <flappleja...@gmail.com>wrote:
>> 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
>> On Mon, Apr 6, 2009 at 3:56 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>>> 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
>>> 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
On Mon, Apr 6, 2009 at 4:50 PM, Mike Brown <mbrow...@gmail.com> wrote: > Remember you can't use a parameter to an Attribute unless it's a compile > time constant or an enum.
> On Mon, Apr 6, 2009 at 4:45 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>> 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 ) >> { >> .... >> }
>> 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
>> On Mon, Apr 6, 2009 at 10:35 PM, Josh Smith <flappleja...@gmail.com>wrote:
>>> 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
>>> On Mon, Apr 6, 2009 at 3:56 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>>>> 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
>>>> 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
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.
On Mon, Apr 6, 2009 at 10:51 PM, Josh Smith <flappleja...@gmail.com> wrote: > In Marlon's setup, the message IDs can be const strings exposed off some > class. That should work ok.
> On Mon, Apr 6, 2009 at 4:50 PM, Mike Brown <mbrow...@gmail.com> wrote:
>> Remember you can't use a parameter to an Attribute unless it's a compile >> time constant or an enum.
>> On Mon, Apr 6, 2009 at 4:45 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>>> 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 ) >>> { >>> .... >>> }
>>> 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
>>> On Mon, Apr 6, 2009 at 10:35 PM, Josh Smith <flappleja...@gmail.com>wrote:
>>>> 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
>>>> On Mon, Apr 6, 2009 at 3:56 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>>>>> 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
>>>>> 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
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)
On Mon, Apr 6, 2009 at 10:53 PM, Marlon Grech <marlongr...@gmail.com> wrote: > 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.
> On Mon, Apr 6, 2009 at 10:51 PM, Josh Smith <flappleja...@gmail.com>wrote:
>> In Marlon's setup, the message IDs can be const strings exposed off some >> class. That should work ok.
>> On Mon, Apr 6, 2009 at 4:50 PM, Mike Brown <mbrow...@gmail.com> wrote:
>>> Remember you can't use a parameter to an Attribute unless it's a compile >>> time constant or an enum.
>>> On Mon, Apr 6, 2009 at 4:45 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>>>> 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 ) >>>> { >>>> .... >>>> }
>>>> 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
>>>> On Mon, Apr 6, 2009 at 10:35 PM, Josh Smith <flappleja...@gmail.com>wrote:
>>>>> 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
>>>>> On Mon, Apr 6, 2009 at 3:56 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>>>>>> 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
>>>>>> 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
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.<http://msdn.microsoft.com/en-us/magazine/dd569749.aspx>
On Mon, Apr 6, 2009 at 4:53 PM, Marlon Grech <marlongr...@gmail.com> wrote: > 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.
> On Mon, Apr 6, 2009 at 10:51 PM, Josh Smith <flappleja...@gmail.com>wrote:
>> In Marlon's setup, the message IDs can be const strings exposed off some >> class. That should work ok.
>> On Mon, Apr 6, 2009 at 4:50 PM, Mike Brown <mbrow...@gmail.com> wrote:
>>> Remember you can't use a parameter to an Attribute unless it's a compile >>> time constant or an enum.
>>> On Mon, Apr 6, 2009 at 4:45 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>>>> 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 ) >>>> { >>>> .... >>>> }
>>>> 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
>>>> On Mon, Apr 6, 2009 at 10:35 PM, Josh Smith <flappleja...@gmail.com>wrote:
>>>>> 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
>>>>> On Mon, Apr 6, 2009 at 3:56 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>>>>>> 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
>>>>>> 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
On Mon, Apr 6, 2009 at 11:28 PM, Mike Brown <mbrow...@gmail.com> wrote: > 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.<http://msdn.microsoft.com/en-us/magazine/dd569749.aspx>
> On Mon, Apr 6, 2009 at 4:53 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>> 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.
>> On Mon, Apr 6, 2009 at 10:51 PM, Josh Smith <flappleja...@gmail.com>wrote:
>>> In Marlon's setup, the message IDs can be const strings exposed off some >>> class. That should work ok.
>>> On Mon, Apr 6, 2009 at 4:50 PM, Mike Brown <mbrow...@gmail.com> wrote:
>>>> Remember you can't use a parameter to an Attribute unless it's a compile >>>> time constant or an enum.
>>>> On Mon, Apr 6, 2009 at 4:45 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>>>>> 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 ) >>>>> { >>>>> .... >>>>> }
>>>>> 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
>>>>> On Mon, Apr 6, 2009 at 10:35 PM, Josh Smith <flappleja...@gmail.com>wrote:
>>>>>> 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
>>>>>> On Mon, Apr 6, 2009 at 3:56 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>>>>>>> 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
>>>>>>> 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
On Mon, Apr 6, 2009 at 5:32 PM, Marlon Grech <marlongr...@gmail.com> wrote: > Why would you want the Mediator as a service on another machine? I don't > think this needs that kind of scalability
> On Mon, Apr 6, 2009 at 11:28 PM, Mike Brown <mbrow...@gmail.com> wrote:
>> 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.<http://msdn.microsoft.com/en-us/magazine/dd569749.aspx>
>> On Mon, Apr 6, 2009 at 4:53 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>>> 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.
>>> On Mon, Apr 6, 2009 at 10:51 PM, Josh Smith <flappleja...@gmail.com>wrote:
>>>> In Marlon's setup, the message IDs can be const strings exposed off some >>>> class. That should work ok.
>>>> On Mon, Apr 6, 2009 at 4:50 PM, Mike Brown <mbrow...@gmail.com> wrote:
>>>>> Remember you can't use a parameter to an Attribute unless it's a >>>>> compile time constant or an enum.
>>>>> On Mon, Apr 6, 2009 at 4:45 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>>>>>> 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 ) >>>>>> { >>>>>> .... >>>>>> }
>>>>>> 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
>>>>>> On Mon, Apr 6, 2009 at 10:35 PM, Josh Smith <flappleja...@gmail.com >>>>>> > wrote:
>>>>>>> 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
>>>>>>> On Mon, Apr 6, 2009 at 3:56 PM, Marlon Grech <marlongr...@gmail.com >>>>>>> > wrote:
>>>>>>>> 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
>>>>>>>> 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
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.
> 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)
> On Mon, Apr 6, 2009 at 10:53 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>> 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.
>> On Mon, Apr 6, 2009 at 10:51 PM, Josh Smith <flappleja...@gmail.com>wrote:
>>> In Marlon's setup, the message IDs can be const strings exposed off some >>> class. That should work ok.
>>> On Mon, Apr 6, 2009 at 4:50 PM, Mike Brown <mbrow...@gmail.com> wrote:
>>>> Remember you can't use a parameter to an Attribute unless it's a compile >>>> time constant or an enum.
>>>> On Mon, Apr 6, 2009 at 4:45 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>>>>> 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 ) >>>>> { >>>>> .... >>>>> }
>>>>> 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
>>>>> On Mon, Apr 6, 2009 at 10:35 PM, Josh Smith <flappleja...@gmail.com>wrote:
>>>>>> 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
>>>>>> On Mon, Apr 6, 2009 at 3:56 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>>>>>>> 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
>>>>>>> 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
On Mon, Apr 6, 2009 at 11:28 PM, Mike Brown <mbrow...@gmail.com> wrote:
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.
On Mon, Apr 6, 2009 at 4:53 PM, Marlon Grech <marlongr...@gmail.com> wrote:
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.
On Mon, Apr 6, 2009 at 10:51 PM, Josh Smith <flappleja...@gmail.com> wrote:
In Marlon's setup, the message IDs can be const strings exposed off some class. That should work ok.
On Mon, Apr 6, 2009 at 4:50 PM, Mike Brown <mbrow...@gmail.com> wrote:
Remember you can't use a parameter to an Attribute unless it's a compile time constant or an enum.
On Mon, Apr 6, 2009 at 4:45 PM, Marlon Grech <marlongr...@gmail.com> wrote:
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
On Mon, Apr 6, 2009 at 10:35 PM, Josh Smith <flappleja...@gmail.com> wrote:
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
On Mon, Apr 6, 2009 at 3:56 PM, Marlon Grech <marlongr...@gmail.com> wrote:
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; }
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
> On Mon, Apr 6, 2009 at 11:28 PM, Mike Brown <mbrow...@gmail.com> wrote:
> 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.<http://msdn.microsoft.com/en-us/magazine/dd569749.aspx>
> On Mon, Apr 6, 2009 at 4:53 PM, Marlon Grech <marlongr...@gmail.com>wrote:
> 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.
> On Mon, Apr 6, 2009 at 10:51 PM, Josh Smith <flappleja...@gmail.com>wrote:
> In Marlon's setup, the message IDs can be const strings exposed off some > class. That should work ok.
> On Mon, Apr 6, 2009 at 4:50 PM, Mike Brown <mbrow...@gmail.com> wrote:
> Remember you can't use a parameter to an Attribute unless it's a compile > time constant or an enum.
> On Mon, Apr 6, 2009 at 4:45 PM, Marlon Grech <marlongr...@gmail.com>wrote:
> 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 ) > { > .... > }
> 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
> On Mon, Apr 6, 2009 at 10:35 PM, Josh Smith <flappleja...@gmail.com>wrote:
> 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
> On Mon, Apr 6, 2009 at 3:56 PM, Marlon Grech <marlongr...@gmail.com>wrote:
> 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
> 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
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)
On Tue, Apr 7, 2009 at 6:17 AM, Josh Smith <flappleja...@gmail.com> wrote: > 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.
>> 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)
>> On Mon, Apr 6, 2009 at 10:53 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>>> 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.
>>> On Mon, Apr 6, 2009 at 10:51 PM, Josh Smith <flappleja...@gmail.com>wrote:
>>>> In Marlon's setup, the message IDs can be const strings exposed off some >>>> class. That should work ok.
>>>> On Mon, Apr 6, 2009 at 4:50 PM, Mike Brown <mbrow...@gmail.com> wrote:
>>>>> Remember you can't use a parameter to an Attribute unless it's a >>>>> compile time constant or an enum.
>>>>> On Mon, Apr 6, 2009 at 4:45 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>>>>>> 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 ) >>>>>> { >>>>>> .... >>>>>> }
>>>>>> 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
>>>>>> On Mon, Apr 6, 2009 at 10:35 PM, Josh Smith <flappleja...@gmail.com >>>>>> > wrote:
>>>>>>> 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
>>>>>>> On Mon, Apr 6, 2009 at 3:56 PM, Marlon Grech <marlongr...@gmail.com >>>>>>> > wrote:
>>>>>>>> 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
>>>>>>>> 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
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-disciples@googlegroups.com [mailto:wpf-disciples@googlegroups.com] On Behalf Of Josh Smith Sent: Tuesday, April 07, 2009 6:18 AM To: wpf-disciples@googlegroups.com Subject: [WPF Disciples] Re: New Mediator
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.
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)
On Mon, Apr 6, 2009 at 10:53 PM, Marlon Grech <marlongr...@gmail.com> wrote:
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.
On Mon, Apr 6, 2009 at 10:51 PM, Josh Smith <flappleja...@gmail.com> wrote:
In Marlon's setup, the message IDs can be const strings exposed off some class. That should work ok.
On Mon, Apr 6, 2009 at 4:50 PM, Mike Brown <mbrow...@gmail.com> wrote:
Remember you can't use a parameter to an Attribute unless it's a compile time constant or an enum.
On Mon, Apr 6, 2009 at 4:45 PM, Marlon Grech <marlongr...@gmail.com> wrote:
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
On Mon, Apr 6, 2009 at 10:35 PM, Josh Smith <flappleja...@gmail.com> wrote:
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
On Mon, Apr 6, 2009 at 3:56 PM, Marlon Grech <marlongr...@gmail.com> wrote:
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
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
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
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
From: wpf-disciples@googlegroups.com [mailto:wpf-disciples@googlegroups.com] On Behalf Of Laurent Bugnion, GalaSoft [MVP, MCP] Sent: Tuesday, April 07, 2009 11:05 AM To: wpf-disciples@googlegroups.com Subject: [WPF Disciples] Re: New Mediator
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-disciples@googlegroups.com [mailto:wpf-disciples@googlegroups.com] On Behalf Of Josh Smith Sent: Tuesday, April 07, 2009 6:18 AM To: wpf-disciples@googlegroups.com Subject: [WPF Disciples] Re: New Mediator
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.
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)
On Mon, Apr 6, 2009 at 10:53 PM, Marlon Grech <marlongr...@gmail.com> wrote:
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.
On Mon, Apr 6, 2009 at 10:51 PM, Josh Smith <flappleja...@gmail.com> wrote:
In Marlon's setup, the message IDs can be const strings exposed off some class. That should work ok.
On Mon, Apr 6, 2009 at 4:50 PM, Mike Brown <mbrow...@gmail.com> wrote:
Remember you can't use a parameter to an Attribute unless it's a compile time constant or an enum.
On Mon, Apr 6, 2009 at 4:45 PM, Marlon Grech <marlongr...@gmail.com> wrote:
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
On Mon, Apr 6, 2009 at 10:35 PM, Josh Smith <flappleja...@gmail.com> wrote:
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
On Mon, Apr 6, 2009 at 3:56 PM, Marlon Grech <marlongr...@gmail.com> wrote:
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
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
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
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 18:59:00
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.
From: wpf-disciples@googlegroups.com [mailto:wpf-disciples@googlegroups.com] On Behalf Of Laurent Bugnion, GalaSoft [MVP, MCP] Sent: Tuesday, April 07, 2009 5:32 AM To: wpf-disciples@googlegroups.com Subject: [WPF Disciples] Re: New Mediator
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
From: wpf-disciples@googlegroups.com [mailto:wpf-disciples@googlegroups.com] On Behalf Of Laurent Bugnion, GalaSoft [MVP, MCP] Sent: Tuesday, April 07, 2009 11:05 AM To: wpf-disciples@googlegroups.com Subject: [WPF Disciples] Re: New Mediator
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-disciples@googlegroups.com [mailto:wpf-disciples@googlegroups.com] On Behalf Of Josh Smith Sent: Tuesday, April 07, 2009 6:18 AM To: wpf-disciples@googlegroups.com Subject: [WPF Disciples] Re: New Mediator
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.
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)
On Mon, Apr 6, 2009 at 10:53 PM, Marlon Grech <marlongr...@gmail.com> wrote:
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.
On Mon, Apr 6, 2009 at 10:51 PM, Josh Smith <flappleja...@gmail.com> wrote:
In Marlon's setup, the message IDs can be const strings exposed off some class. That should work ok.
On Mon, Apr 6, 2009 at 4:50 PM, Mike Brown <mbrow...@gmail.com> wrote:
Remember you can't use a parameter to an Attribute unless it's a compile time constant or an enum.
On Mon, Apr 6, 2009 at 4:45 PM, Marlon Grech <marlongr...@gmail.com> wrote:
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
On Mon, Apr 6, 2009 at 10:35 PM, Josh Smith <flappleja...@gmail.com> wrote:
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
On Mon, Apr 6, 2009 at 3:56 PM, Marlon Grech <marlongr...@gmail.com> wrote:
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
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
On Behalf Of Shawn Wildermuth Sent: Tuesday, April 07, 2009 11:49 AM To: wpf-disciples@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.
From: wpf-disciples@googlegroups.com [mailto:wpf-disciples@googlegroups.com] On Behalf Of Laurent Bugnion, GalaSoft [MVP, MCP] Sent: Tuesday, April 07, 2009 5:32 AM To: wpf-disciples@googlegroups.com Subject: [WPF Disciples] Re: New Mediator
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
From: wpf-disciples@googlegroups.com [mailto:wpf-disciples@googlegroups.com] On Behalf Of Laurent Bugnion, GalaSoft [MVP, MCP] Sent: Tuesday, April 07, 2009 11:05 AM To: wpf-disciples@googlegroups.com Subject: [WPF Disciples] Re: New Mediator
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-disciples@googlegroups.com [mailto:wpf-disciples@googlegroups.com] On Behalf Of Josh Smith Sent: Tuesday, April 07, 2009 6:18 AM To: wpf-disciples@googlegroups.com Subject: [WPF Disciples] Re: New Mediator
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.
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)
On Mon, Apr 6, 2009 at 10:53 PM, Marlon Grech <marlongr...@gmail.com> wrote:
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.
On Mon, Apr 6, 2009 at 10:51 PM, Josh Smith <flappleja...@gmail.com> wrote:
In Marlon's setup, the message IDs can be const strings exposed off some class. That should work ok.
On Mon, Apr 6, 2009 at 4:50 PM, Mike Brown <mbrow...@gmail.com> wrote:
Remember you can't use a parameter to an Attribute unless it's a compile time constant or an enum.
On Mon, Apr 6, 2009 at 4:45 PM, Marlon Grech <marlongr...@gmail.com> wrote:
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
On Mon, Apr 6, 2009 at 10:35 PM, Josh Smith <flappleja...@gmail.com> wrote:
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
On Mon, Apr 6, 2009 at 3:56 PM, Marlon Grech <marlongr...@gmail.com> wrote:
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
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.
On Tue, Apr 7, 2009 at 3:46 AM, Marlon Grech <marlongr...@gmail.com> wrote: > 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)
> On Tue, Apr 7, 2009 at 6:17 AM, Josh Smith <flappleja...@gmail.com> wrote:
>> 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.
>>> 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)
>>> On Mon, Apr 6, 2009 at 10:53 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>>>> 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.
>>>> On Mon, Apr 6, 2009 at 10:51 PM, Josh Smith <flappleja...@gmail.com>wrote:
>>>>> In Marlon's setup, the message IDs can be const strings exposed off >>>>> some class. That should work ok.
>>>>> On Mon, Apr 6, 2009 at 4:50 PM, Mike Brown <mbrow...@gmail.com> wrote:
>>>>>> Remember you can't use a parameter to an Attribute unless it's a >>>>>> compile time constant or an enum.
>>>>>> On Mon, Apr 6, 2009 at 4:45 PM, Marlon Grech <marlongr...@gmail.com>wrote:
>>>>>>> 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 ) >>>>>>> { >>>>>>> .... >>>>>>> }
>>>>>>> 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
>>>>>>> On Mon, Apr 6, 2009 at 10:35 PM, Josh Smith < >>>>>>> flappleja...@gmail.com> wrote:
>>>>>>>> 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
>>>>>>>> On Mon, Apr 6, 2009 at 3:56 PM, Marlon Grech < >>>>>>>> marlongr...@gmail.com> wrote:
>>>>>>>>> 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
>>>>>>>>> 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