Handling Corner Cases of the NotifyPropertyChanged Aspect

Postsharp includes a number of attributes for customizing the Model Pattern’s behaviour and for handling special dependencies.

This topic contains the following sections:

Ignoring Changes to Properties

Use the IgnoreAutoChangeNotificationAttribute class attribute to prevent an OnPropertyChanged event from being invoked when setting a property. For example, the CustomerModel class contains a Country property amongst others:

C#
[NotifyPropertyChanged]
public class CustomerModel 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 

    public string Phone { get; set; } 
    public string Mobile { get; set; } 
    public string Email { get; set; } 
    public string Country { get; set;}
}

To prevent a property notification from being invoked when the Country’s value is set, simply place the IgnoreAutoChangeNotificationAttribute attribute above the property:

C#
[NotifyPropertyChanged]
public class CustomerModel 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public string Phone { get; set; } 
    public string Mobile { get; set; } 
    public string Email { get; set; } 

    [IgnoreAutoChangeNotification]
    public string Country { get; set;}
}
Handling Virtual Calls, References, and Delegates in a Get Accessor

If a get accessor calls a virtual method from its class or a delegate, or references a property of another object (without using canonical form this.field.Property), PostSharp will generate an error because it cannot resolve such a dependency at build time. To suppress this error, you can add the [SafeForDependencyAnalysisAttribute] custom attribute to the property accessor (or in any method used by the property accessor). This custom attribute instructs PostSharp that the property accessor is “safe” – in other words, it contains only dependencies in the canonical form this.field.Property.

For example, say CustomerModel contains a virtual method called ValidateCountry() which is used by the get accessor of its Country property:

C#
[NotifyPropertyChanged]
public class CustomerModel 
{ 
  // Details skipped.

protected virtual bool ValidateCountry(string s)
{
  if (s!=null)
    return true;
  else
    return false;
}

  public string Country 
  { 
    get
    {
      if(this.ValidateCountry(value))
        return value;
      else
       return null;
    }
    set;
  }
}

In this situation the property relies on a virtual method which PostSharp cannot resolve at build time, so the SafeForDependencyAnalysisAttribute attribute can be placed on the Country property suppress this error:

C#
[NotifyPropertyChanged]
public class CustomerModel 
{ 
   // Details skipped.

  public virtual bool Test(string s)
  {
    if (s!=null)
      return true;
    else
      return false;
  }

  [SafeForDependencyAnalysisAttribute]
  public string Country 
  { 
    get
    {
      if(this.test(value) == true)
        return value;
      else
       return null;
    }
    set;
  }
}
Note Note

By using SafeForDependencyAnalysisAttribute, you are taking the responsibility that your code only has dependencies that are given either in the canonical form of this.field.Property either explicitly using the On() construct (see the next section). If you are using this custom attribute but have non-canonical dependencies, some property changes may not be detected in which case no notification will be generated.

Handling Local Variables

Properties may depend on a property of another object, and sometimes this object must be stored in a local variable. Most of the times, PostSharp is able to analyze chains of dependencies in properties that are dependent on a property of a local variable. However, when the variable is assigned in a loop or in an exception handler, the analysis cannot be executed.

If PostSharp does not understand your code, you need to use the SafeForDependencyAnalysisAttribute attribute and the Depends.On() method as described above.

Handling Dependencies on Pure Methods

Often times an object will depend on a method which is solely dependent on its input parameters to produce an output (e.g. a static method). Consider the following variation to CustomerModel where the ValidPhoneNumber property logic has been moved into a static method called GetValidPhoneNumber() which exists in a separate helper class called ContactHelper:

C#
public class ContactHelper
{
  [Pure]
  public static string GetValidPhoneNumber(string firstPhoneNumber, string secondPhoneNumber)
  {
    if(firstPhoneNumber != null)
      return firstPhoneNumber;
    else if (secondPhoneNumber != null)
      return secondPhoneNumber;
    else
      return null;    
  }
}

[NotifyPropertyChanged]
public class CustomerModel 
{ 
  public Contact PrimaryContact{get; set;}
  public Contact SecondaryContact{get; set;}

  public string ValidPhoneNumber
  { 
    get {
      return ContactHelper.GetValidPhoneNumber(this.PrimaryContact.Phone, this.SecondaryContact.Phone);
    }
  }
}

Since GetValidPhoneNumber() is a standalone method of another class, it is not analyzed. Therefore the PureAttribute attribute needs to be applied to this method to acknowledge this dependency.

See Also