The solution I found to be the more easier to use is to create an attribute which should be placed above the properties I want to update, giving to that attribute the name of the properties to look at:

[AttributeUsage(AttributeTargets.Property)]
public class NotifyWith : Attribute
{
    private readonly string[] notifyWithProperties;

    public NotifyWith(params string[] notifyWithProperties)
    {
        this.notifyWithProperties = notifyWithProperties;
    }

    public IEnumerable<string> NotifyWithProperties { [DebuggerStepThrough] get { return notifyWithProperties; } }
}

This will allow us to use it like that:

[NotifyPropertyChanged]
public class Test
{
    public string FirstName { get; set; }
    public string LasttName { get; set; }

    [NotifyWith("FirstName", "LastName")]
    public string FullName { get { return FirstName + " " + LasttName; } }
}

This will tell the aspect to fire OnPropertyChanged for the property FullName when FirstName or LastName are modified.

Now, let's alter the aspect.

The first thing we have to do, is to enumerate all the properties of the type affected by the aspect, to find all those which have the NotifyWith attribute. For those properties, we will then have to get the attribute, and use the NotifyWithProperties property to get the properties to watch. We will finally have to fill a Dictionary which will track the relationships between the "parent" and "children" properties.

We will execute this process, and this is a great strength of PostSharp, during the build time. Then PostSharp will serialize the dictionary, allowing us to directly use it at runtime. So, we must override the CompileTimeInitialize function and put our code in here:

public sealed class NotifyPropertyChangedAttribute : InstanceLevelAspect, INotifyPropertyChanged
{
    private Dictionary<string, List<string>> dependencies;

    public override void CompileTimeInitialize(Type type, AspectInfo aspectInfo)
    {
        dependencies = new Dictionary<string, List<string>>();

        foreach (var propertyInfo in type.GetProperties())
        {
            foreach (var propertyName in propertyInfo.GetCustomAttributes(typeof(NotifyWith), true)
                                                    .Cast<NotifyWith>()
                                                    .SelectMany(attribute => attribute.NotifyWithProperties))
            {
                if (!dependencies.ContainsKey(propertyName))
                    dependencies[propertyName] = new List<string>(1);

                dependencies[propertyName].Add(propertyInfo.Name);
            }
        }
    }

    //
}

The final step will now consist of the notification of "children" properties when the value of a "parent" property is modified. We will simply add the following code at the end of the OnPropertySet function:

public void OnPropertySet(LocationInterceptionArgs args)
{
    // Don't go further if the new value is equal to the old one.
    // (Possibly use object.Equals here).
    if (args.Value == args.GetCurrentValue()) return;

    // Actually sets the value.
    args.ProceedSetValue();

    // Invoke method OnPropertyChanged (our, the base one, or the overridden one).
    this.OnPropertyChangedMethod.Invoke(args.Location.Name);

    List<string> dependentValues;
    dependencies.TryGetValue(args.Location.Name, out dependentValues);

    if (dependentValues == null)
        return;

    dependentValues.ForEach(name => OnPropertyChangedMethod.Invoke(name));
}

I've just started to use it, and this is clearly much much more comfortable to use this feature :)

I hope you enjoyed it, and see you later!