Improvements to NotifyPropertyChangedBehavior, Comments?

Sep 3, 2010 at 7:58 AM

I am quite new to unity interception. Autogenenrating code, which I type hundreds of times, looked quite appealing. I am talking of this code (considering a mapped class MyClass with a property Name):

    public string Name {
      get {
        return m_MyClass.Name;
      }
      set {
        if(Name == value) {
          return;
        }

      	m_MyClass.Name = value;

        OnPropertyChanged("Name");
      }
    }

As the example for the NotifyPropertyChangedBehavior is in the Unity 2 help file, I startet looking at it. More or less it generates the following code:

    public string Name {
      get {
        return m_MyClass.Name;
      }
      set {
      	m_MyClass.Name = value;

        OnPropertyChanged("Name");
      }
    }

As this code can rise to event ping pong in certain binding scenerios, I changed the orignal code:

    private IMethodReturn InterceptPropertySet(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) {
      var propertyName = input.MethodBase.Name.Substring(4);

      var returnValue = getNext()(input, getNext);

      var subscribers = propertyChanged;
      if (subscribers != null) {
        subscribers(input.Target, new PropertyChangedEventArgs(propertyName));
      }

      return returnValue;
    }

to:

    private IMethodReturn InterceptPropertySet(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) {
      var propertyName = input.MethodBase.Name.Substring(4);
      object[] propertyIndex = input.Arguments.Cast<object>().
                                 Where((a, index) => index < input.Arguments.Count - 1).
                                 ToArray();
      object propertyTarget = input.Target;
      object propertyOldValue = input.Target.
                                  GetType().
                                  GetProperty(propertyName).
                                  GetValue(propertyTarget, propertyIndex);
      object propertyNewValue = input.Arguments[input.Arguments.Count - 1];

      IMethodReturn returnValue = getNext()(input, getNext);

      NotifySubscribers(propertyTarget, propertyName, propertyOldValue, propertyNewValue);

      return returnValue;
    }

    private void NotifySubscribers(object target, string name, object oldValue, object newValue) {
      if (oldValue == newValue) {
        return;
      }

      var subscribers = propertyChanged;
      if (subscribers == null) {
        return;
      }

      subscribers(target, new PropertyChangedEventArgs(name));
    }

This is not 100% the desired result, but more a:

    public string Name {
      get {
        return m_MyClass.Name;
      }
      set {
        m_MyClass.Name = value;

        if (Name != value) {
          OnPropertyChanged("Name");
        }
      }
    }


but as the event is only thrown at times, when really a change happens, it is the change I wanted to achieve.

As said, I am new two unity 2 interception. Can someone please comment to the code if I solved this modification correct (in the way I wanted it) or I would have coded it better some other way.

Sep 3, 2010 at 9:47 AM

In my studies on the topic I ran into the following link which seems to address a number of issues (to include errors in setter as well as ensuring values have changed).  

INotifyPropertyChanged with Unity Interception AOP
http://shecht.wordpress.com/2009/12/12/inotifypropertychanged-with-unity-interception-aop/

Perhaps it might give you some additional ideas.

Looking to learn from your experiences on the matter I was curious what the "event ping pong" issue was and when it could be a problem?

Sep 5, 2010 at 8:35 AM

Thanks for the link. The code helps to modify my approach with a little more performance and it handles writeonly properties, which in my case would leed to an exception. But it does lack the handling of indexed properties. That´s why I asked in the first place, there are a lot of options to handle.

The problem that IMethodReturn res = getNext()(input, getNext); executes the interceptet classes setter code. So my ultimate goal (to make the code perfect) would be to give a modified input to the call chain, having an empty method.

As for my problems with raising the PropertyChanged event everytime the setter is called regardless of the value:

1. There are some controls out there raising the Format/Parse events not only for user interaction. So the user enters a value, the Format event is triggerd, setting the value. Then the Parse event kicks in setting a value. Then the Format, then Parse..... You get the picture?

2. I rely in my code on this event to handle a dirty flag. So I want it really to be set only in cases where a change actually has happened