Property Notifications

Property Notifications allow your code to automatically get notifications when a certain property of a type has changed, and to react to this change with a callback.

Property notifications are provided at system level by each platform, but Elements also provides a platform-agnostic way to work with them in shared code.

Using property notifications involves three steps:

  1. Enabling individual properties to emit change notifications
  2. Subscribing to observe changes to a property
  3. Handling the callback when actual changes occur

Enabling Properties to Emit Change Notifications

Turning on notification for a property could not be simpler. Simply adding the [Notify] aspect to the property, or – on Oxygene – using the notify keyword instructs the compiler to emit all the necessary boiler-plate code under the hood to enable notifications when the property changes:

type
  Foo = public class 
  public
    [Notify] property MyProperty: String;
    property MyProperty2: String; notify;
  end;
public class Foo
{
    [Notify] public String MyProperty { get;set; }
}
public class Foo {

    @Notify var myProperty: String!
}
public class Foo {

    @Notify public String myProperty { __get; __set; }
}

Notifications use the string value of the property name. You can optionally provide a different name to the [Notify] aspect, if you want changes to the property emit notifications under a different name.

Subscribing to Observe Changes

The easiest way to subscribe to change notifications is to use the Observer class in Elements RTL. An observer expects a target object and property name, as well as at least one Block parameter that will be called when the property changes:

var fFoo := new Foo;
var fObserver := new Observer(lFoo, "MyProperty") begin
  writeLn("property changed!");
end;
var foo = new Foo()
var observer = new Observer(foo, "MyProperty") {
    writeLn("property changed!");
}
let foo = Foo()
let observer = Observer(foo, "myProperty") {
    writeLn("property changed!");
}
var foo = new Foo();
var observer = Observer(foo, "myProperty", () => {
    writeLn("property changed!");
});

To avoid hardcoding the property name as string literal (and the potential for typos that comes with it), the nameOf() system function can be used to obtain the type-safe name of the property at compile time:

new Observer(lFoo, nameOf(lFoo.MyProperty) ...
new Observer(lFoo, nameOf(foo.MyProperty) ...
new Observer(lFoo, nameOf(foo.myProperty) ...

```

new Observer(lFoo, nameOf(foo.myProperty) ...

The block will be called after the property has been changed, this is referred to as the "did change" callback. Optionally, a "will change" callback may be provided as well; this block will be called before the property changes.

"will change" callbacks are only supported on .NET, Cocoa and the Island-backed platforms. On Java, the Observer API allows passing the second callback to maintain API compatibility, but it will never fire.

Note the that optional "will change" block is the third parameter of the Observer constructor, and comes before the (non-optional) "did change" block parameter.

Handling the Callback

Every time the property in question has changed (or will change), the appropriate callback will be fired. The property will be unchanged (i.e. have its old value) in the "will change" callback, and it will have its final new value (including any adjustments made by the property setter) in the "did change" callback.

Note that the callback(s) will still fire every time the property is set, even if its actual value might not have changed.

Platform Details

On .NET, Android, Java and the Island-backed platforms, the [Notify] aspect or keyword will automatically implement the INotifyPropertyChanged interface, and except on Java it will also implement INotifyPropertyChanging.

On .NET and Island, these are system-level interfaces defined in the standard .NET Framework library or Island RTL, respectively. These interfaces work very similar on both platforms, declaring a single Event member that can be subscribed to for change notifications.

On Java, INotifyPropertyChanged is defined in cooper.jar, and wraps together the Java-standard addPropertyChangeListener and removePropertyChangeListener methods, as described here.

On Cocoa, notify implements the standard Key-Value Observation infrastructure of the Objective-C runtime.

The source code for the Observer class is available on Github and provides an illustration for how the platform-specific notification subscription works.

See Also