Walkthrough: Working with Properties that Depend on Other Objects

It’s very common for the properties of one class to be dependent on the properties of another class. For example, a view-model layer will often contain a reference to a model object, and public properties which are in turn forwarded to the underlying properties of this referenced object. In this scenario the view-model component’s properties have a dependency on the referenced model’s properties. Subsequently the referenced model may also have properties which depend on the properties of other objects.

PostSharp’s Model Pattern Library easily handles transitive dependencies. Simply add the NotifyPropertyChangedAttribute class attribute to each class in the dependency chain. This will ensure that property change notifications are propagated up and down the dependency chain. The Model Pattern Library takes care of the rest and will even handle circular dependencies.

In the following set of steps, the CustomerModel class is used as a dependency of a CustomerViewModel class containing FirstName and LastName properties both of which directly map to properties of the CustomerModel class, and a public read only property called FullName, which is calculated based on the value of the underlying customer’s FirstName and LastName properties.

  1. Add the CustomerModel class to your project ensuring that the NotifyPropertyChangedAttribute attribute is included:

    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; }
    }
  2. Setup a view-model class which contains a reference to a CustomerModel object, add properties to get/set the name related fields. References to properties of the CustomersForEditing object should be in the form of this.field.Property (or this.Property.Property), otherwise PostSharp won’t be able to discover the dependencies from your source code.

    C#
    class CustomerViewModel
    {
        CustomerModel model;
    
        public CustomerViewModel(CustomerModel m)
        {
            this.model = m;
        }
    
        public string FirstName { get { return this.model.FirstName; } set { this.model.FirstName = value;}}
    
        public string LastName { get { return this.model.LastName; } set { this.model.LastName = value; }}
    
    }
  3. Add the FullName property and use the same rule as described in the previous step to reference dependent properties:

    C#
    class CustomerViewModel
    {
        CustomerModel model;
    
        public CustomerViewModel(CustomerModel m)
        {
            this.model = m;
        }
        public string FirstName { get { return this.model.FirstName; } set { this.model.FirstName = value;}}
        public string LastName { get { return this.model.LastName; } set { this.model.LastName = value; }}
    
        public string FullName { get {
          return string.Format("{0} {1}", this.model.FirstName, this.model.LastName);
        } }
    
     }
  4. Add the NotifyPropertyChangedAttribute attribute to the class:

    C#
    [NotifyPropertyChanged]
    class CustomerViewModel
    {
        CustomerModel model;
    
        public CustomerViewModel(CustomerModel m)
        {
            this.model = m;
        }
    
        public string FirstName { get { return this.model.FirstName; } set { this.model.FirstName = value;}}
        public string LastName { get { return this.model.LastName; } set { this.model.LastName = value; }}
    
        public string FullName { get {
          return string.Format("{0} {1}", this.model.FirstName, this.model.LastName);
        } }
    
    }

You now have a view-model class which can be used to bridge a view (e.g. an application’s user interface) with the underlying data, and calls to get/set will be propagated across the chain of dependencies.

Note Note

Read the article Handling Corner Cases to learn about referencing properties without using the this.field.Property form.

See Also