Click here to Skip to main content
15,888,968 members
Home / Discussions / C#
   

C#

 
GeneralRe: How to use WeakEventManager with reflection Pin
Sascha Lefèvre24-Jan-16 1:34
professionalSascha Lefèvre24-Jan-16 1:34 
GeneralRe: How to use WeakEventManager with reflection Pin
Kornfeld Eliyahu Peter24-Jan-16 1:38
professionalKornfeld Eliyahu Peter24-Jan-16 1:38 
GeneralRe: How to use WeakEventManager with reflection Pin
Sascha Lefèvre24-Jan-16 1:42
professionalSascha Lefèvre24-Jan-16 1:42 
GeneralRe: How to use WeakEventManager with reflection Pin
Kenneth Haugland24-Jan-16 3:25
mvaKenneth Haugland24-Jan-16 3:25 
GeneralRe: How to use WeakEventManager with reflection Pin
Kornfeld Eliyahu Peter24-Jan-16 3:42
professionalKornfeld Eliyahu Peter24-Jan-16 3:42 
GeneralRe: How to use WeakEventManager with reflection Pin
Kenneth Haugland24-Jan-16 3:47
mvaKenneth Haugland24-Jan-16 3:47 
AnswerRe: How to use WeakEventManager with reflection Pin
Sascha Lefèvre24-Jan-16 2:37
professionalSascha Lefèvre24-Jan-16 2:37 
GeneralRe: How to use WeakEventManager with reflection Pin
Kenneth Haugland24-Jan-16 3:11
mvaKenneth Haugland24-Jan-16 3:11 
This looks very promising indeed. This piece of code is intended to be used in a Mediator, i.a a static instance that you can use to synchronize two or more properties in separate classes. The code is very similar to Sacha Barbers Mediator in his MVVM helper class Cinch, where you can raise an event in a property and it will invoke a delegate to a subroutine (void) in a separate class (in my cases between two ViewModels). I want to change the behavior to update a property if another property changed. The problem is that the connections with the shared (static) Mediator must be of a weak type, if not you might get a lot of memory leaks as a direct consequence of the strong references the normal event creates.

To do this I created an attribute that you can decorate a property with:
C#
[AttributeUsage(AttributeTargets.Property)]
public sealed class PropertyMediatorAttribute : Attribute
{
    /// <summary>
    /// Message key
    /// </summary>
    public string MessageKey { get; private set; }

    /// <summary>
    /// Default constructor
    /// </summary>
    public PropertyMediatorAttribute()
    {
        MessageKey = null;
    }

    /// <summary>
    /// Constructor that takes a message key
    /// </summary>
    /// <param name="messageKey">Message Key</param>
    public PropertyMediatorAttribute(string messageKey)
    {
        MessageKey = messageKey;
    }
}


My full code so far is (it does work but it won't allow the connected classes to be garbage collected):
C#
public class PropertyMediator
   {
       #region Data
       static readonly PropertyMediator instance = new PropertyMediator();
       static readonly object syncLock = new object();
       private readonly Dictionary<string, List<WeakPropertyDescriptor>> _registeredListners =
           new Dictionary<string, List<WeakPropertyDescriptor>>();
       #endregion

       #region Ctor
       static PropertyMediator()
       {

       }

       private PropertyMediator()
       {

       }
       #endregion

       /// <summary>
       /// Singleton Instance
       /// </summary>
       public static PropertyMediator Instance
       {
           get
           {
               return instance;
           }
       }


       internal class WeakPropertyDescriptor
       {
           public PropertyMediator _MethodOwner;
           public WeakReference _sender;
           public string _PropertyName;
           public string _MessageKey;
           public EventHandler handler;

           public WeakPropertyDescriptor(PropertyMediator MethodOwner, Object sender, string PropertyName, string MessageKey)
           {
               _MethodOwner = MethodOwner;
               _sender = new WeakReference(sender);
               _PropertyName = PropertyName;
               _MessageKey = MessageKey;

               handler = (s, e) => _MethodOwner.NotifyColleaguesOfValueChanged(s, e, _MessageKey, _PropertyName);
               PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(_sender.Target);
               System.ComponentModel.PropertyDescriptor myProperty = properties.Find(PropertyName, false);
               myProperty.AddValueChanged(_sender.Target, handler);

               //Type type = _sender.Target.GetType();

               //// create an instance of that type
               //var instance = Activator.CreateInstance(type);
               //var tt = 5;

            //   WeakEventManager <instance, handler >.AddHandler(_sender.Target, _PropertyName, handler);

           //    ((INotifyPropertyChanged)_sender.Target).PropertyChanged += handler;
           }

       }

       internal void NotifyColleaguesOfValueChanged(object sender, EventArgs e, string key, string PropertyName)
       {

           object message = sender.GetType().GetProperty(PropertyName).GetValue(sender, null);

           List<WeakPropertyDescriptor> wr;
           if (_registeredListners.TryGetValue(key, out wr))
           {
               foreach (WeakPropertyDescriptor item in wr)
               {
                   // Dummy test to check wheter or not to remove items form the list
                   if (item._sender.IsAlive)
                   {
                       PropertyInfo MyProperty = item._sender.Target.GetType().GetProperty(item._PropertyName, BindingFlags.Public | BindingFlags.Instance);

                       // If the property is different then the raised events property, change it
                       if (message != MyProperty.GetValue(item._sender.Target, null))
                       {
                           if (null != MyProperty && MyProperty.CanWrite)
                           {
                               MyProperty.SetValue(item._sender.Target, message, null);
                           }
                       }
                   }
                   else
                   {

                   }


               }
           }

       }

       /// <summary>
       /// http://www.codeproject.com/Articles/217670/The-Third-Way-of-Change-Notification-The-ValueChan
       /// </summary>
       /// <param name="source"></param>
       private void RemoveSourceFromValueChangedEventManager(object source)
       {
           // Remove the source from the ValueChangedEventManager.
           Assembly assembly = Assembly.GetAssembly(typeof(FrameworkElement));
           Type type = assembly.GetType("MS.Internal.Data.ValueChangedEventManager");
           PropertyInfo propertyInfo = type.GetProperty("CurrentManager", BindingFlags.NonPublic | BindingFlags.Static);
           MethodInfo currentManagerGetter = propertyInfo.GetGetMethod(true);
           object manager = currentManagerGetter.Invoke(null, null);
           MethodInfo remove = type.GetMethod("Remove", BindingFlags.NonPublic | BindingFlags.Instance);
           remove.Invoke(manager, new object[] { source });
           // The code above removes the instances of ValueChangedRecord from the
           // WeakEventTable, but they are still rooted by the property descriptors of
           // the source object. We need to clean them out of the property descriptors
           // as well, to allow them to be garbage collected. (Which is necessary
           // because they contain a hard reference to the source, which is what we
           // really want garbage collected.)
           FieldInfo valueChangedHandlersInfo = typeof(PropertyDescriptor).GetField("valueChangedHandlers", BindingFlags.Instance | BindingFlags.NonPublic);
           PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(source);

           foreach (PropertyDescriptor pd in pdc)
           {
               Hashtable changeHandlers = (Hashtable)valueChangedHandlersInfo.GetValue(pd);
               if (changeHandlers != null)
               {
                   changeHandlers.Remove(source);
               }
           }
       }

       private void RegisterProperty(string _MessageKey, object sender, string PropertyName)
       {
           WeakPropertyDescriptor WeakPropertyReferance = new WeakPropertyDescriptor(this, sender, PropertyName, _MessageKey);
           List<WeakPropertyDescriptor> wr;
           if (_registeredListners.TryGetValue(_MessageKey, out wr))
           {

               if (wr != null)
               {
                   wr.Add(WeakPropertyReferance);
               }
           }
           else
           {
               wr = new List<WeakPropertyDescriptor>();
               wr.Add(WeakPropertyReferance);
               _registeredListners[_MessageKey] = wr;

           }

       }

       public void Register(object view)
       {
           // Look at all instance/static properties on this object type.
           foreach (var mi in view.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
           {
               //  var test = mi.GetCustomAttributes(typeof(PropertyMediatorAttribute));
               // See if we have a target attribute - if so, register the method as a handler.
               foreach (var att in mi.GetCustomAttributes(typeof(PropertyMediatorAttribute)))
               {
                   var mha = (PropertyMediatorAttribute)att;
                   // Removes all subscribed PropertyDiscriptors from the object
                 //  RemoveSourceFromValueChangedEventManager(view);
                   RegisterProperty(mha.MessageKey, view, mi.Name);
               }
           }
       }

       public void UnRegister(object view)
       {
           // Look at all instance/static properties on this object type.
           foreach (var mi in view.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
           {
               //  var test = mi.GetCustomAttributes(typeof(PropertyMediatorAttribute));
               // See if we have a target attribute - if so, register the method as a handler.
               foreach (var att in mi.GetCustomAttributes(typeof(PropertyMediatorAttribute)))
               {
                   var mha = (PropertyMediatorAttribute)att;
                   RemoveSourceFromValueChangedEventManager(view);


               }
           }
       }

   }


The usage is rather simple:
C#
public class A : NotifierBase
{
    public A()
    {
        PropertyMediator.Instance.Register(this);

    }


    private string m_Name = "test";
    [PropertyMediatorAttribute("MyProp")]
    public string Name
    {
        get { return m_Name; }
        set
        {
            SetProperty(ref m_Name, value);
        }
    }

    ~A()
    {
        PropertyMediator.Instance.UnRegister(this);
    }

}

GeneralRe: How to use WeakEventManager with reflection Pin
Sascha Lefèvre24-Jan-16 4:33
professionalSascha Lefèvre24-Jan-16 4:33 
GeneralRe: How to use WeakEventManager with reflection Pin
Kenneth Haugland24-Jan-16 4:45
mvaKenneth Haugland24-Jan-16 4:45 
GeneralRe: How to use WeakEventManager with reflection Pin
Sascha Lefèvre24-Jan-16 6:14
professionalSascha Lefèvre24-Jan-16 6:14 
GeneralRe: How to use WeakEventManager with reflection Pin
Kenneth Haugland24-Jan-16 17:34
mvaKenneth Haugland24-Jan-16 17:34 
GeneralRe: How to use WeakEventManager with reflection Pin
Kenneth Haugland24-Jan-16 22:45
mvaKenneth Haugland24-Jan-16 22:45 
AnswerRe: How to use WeakEventManager with reflection Pin
Pete O'Hanlon24-Jan-16 7:03
mvePete O'Hanlon24-Jan-16 7:03 
GeneralRe: How to use WeakEventManager with reflection Pin
Kenneth Haugland24-Jan-16 17:38
mvaKenneth Haugland24-Jan-16 17:38 
GeneralRe: How to use WeakEventManager with reflection Pin
Pete O'Hanlon24-Jan-16 21:25
mvePete O'Hanlon24-Jan-16 21:25 
AnswerRe: How to use WeakEventManager with reflection Pin
Kenneth Haugland25-Jan-16 7:42
mvaKenneth Haugland25-Jan-16 7:42 
GeneralRe: How to use WeakEventManager with reflection Pin
Sascha Lefèvre25-Jan-16 10:28
professionalSascha Lefèvre25-Jan-16 10:28 
QuestionHow to generate Dynamic buttons in C# from Database Values? Pin
Member 1224271723-Jan-16 19:54
Member 1224271723-Jan-16 19:54 
AnswerRe: How to generate Dynamic buttons in C# from Database Values? Pin
Mycroft Holmes23-Jan-16 20:13
professionalMycroft Holmes23-Jan-16 20:13 
GeneralRe: How to generate Dynamic buttons in C# from Database Values? Pin
Member 1224271723-Jan-16 20:25
Member 1224271723-Jan-16 20:25 
GeneralRe: How to generate Dynamic buttons in C# from Database Values? Pin
Mycroft Holmes23-Jan-16 20:30
professionalMycroft Holmes23-Jan-16 20:30 
Questionhow to implement this code for multiple clients using c sharp Pin
Member 1061979722-Jan-16 22:32
Member 1061979722-Jan-16 22:32 
AnswerRe: how to implement this code for multiple clients using c sharp Pin
OriginalGriff22-Jan-16 23:01
mveOriginalGriff22-Jan-16 23:01 
QuestionRe: how to implement this code for multiple clients using c sharp Pin
Paul Conrad23-Jan-16 6:00
professionalPaul Conrad23-Jan-16 6:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.