PropertyName - The descriptor specifying a property's name.
Examples: "FirstName", "Address"
If the 'PropertyName' refers to a property of a value type or a non-persistent property, the control that is bound to it will receive this property's value. If the 'PropertyName' refers to a persistent property, the control will receive a collection of objects referenced by the 'PropertyName' (if this property only denotes a "one-to-one" relationship, the collection will contain only one item).
When the 'PropertyName' refers to a persistent property, returning a collection is required to support binding to sub-properties. See below.
PropertyName.NestedPropertyName - The descriptor referring to a sub-property of a specific property.
The dot (".") symbol is used to delimit sub-properties. The number of nested levels is not limited.
In ASP.NET, to access sub-properties via the Eval function, use the PropertyName.SubProperty. Note that two-way binding via the Bind function is not supported for XPO sub-properties in ASP.NET applications.
Non-aggregated nested property descriptors are not editable by design and you have to manually maintain data saving and cancellation in this case.
This - represents a reference to a persistent object.
PropertyName! - A descriptor with a name ending with an exclamation point ("!") represents a reference to the persistent object identified by the 'PropertyName' property. It can be applied to a persistent property only.
This descriptor allows bound controls to work with the property value (a reference) directly. You can use this property descriptor to bind a lookup editor (e.g. the LookUpEdit control) which has its ValueMember property set to This. See How to: Bind an XPCollection to a LookUp, for an example.
The property descriptor with ! provides binding to lookup editors in most, but not all cases. Some Windows Forms controls cannot work with a ValueMember of the Object type (for example, a standard ComboBox only supports binding via its Text property). As for ASP.NET, it's impossible to work with object references on the client-side (the .NET object model is not supported in scripts). The following descriptor covers this situation.
PropertyName!Key - A descriptor with a name ending with !Key represents a key of the persistent object identified by the 'PropertyName' property. It can be applied to a persistent property only.
This property descriptor matches the value of an object's key property (for objects derived from the XPObject class, this value is specified by the autogenerated Oid field). You can use this property descriptor to bind a lookup editor (e.g. the LookUpEdit control) which has its ValueMember property set to Oid. See How to: Bind an XPCollection to a LookUp for an example.
When a new value is being set to the PropertyName!Key property, the Session.GetObjectByKey function is called to find an XPObject by the key being assigned. Then, the found object is assigned to the PropertyName. Note that the Session.GetObjectByKey function can locate only those objects which are saved in the data store.
Using "PropertyName!Key" vs. "PropertyName.Oid"
This question arises when binding controls to a property of a persistent class type. The most common example of such controls is lookup editors. Generally, you shouldn't bind these controls to PropertyName.Oid, because when a new value is set to this type of property, the PropertyName's Oid field is changed instead of the PropertyName itself. Obviously, this is not the expected behavior when you edit a PropertyName via a lookup editor. You must bind it to PropertyName!Key instead. In this case, XPO will find an object by its key and change the reference, as required. You can also use PropertyName! to bind to a lookup editor - internally it doesn't work the same way as PropertyName!Key, but produces the same result.
Using "PropertyName!" vs. "PropertyName!Key" in Lookup Editors
In ASP.NET applications, you must use descriptors ending with !Key for lookup editors. With Windows Forms applications, you can also use descriptors ending with !. However, you should always use the !Key descriptor for lookup columns in the GridView, if their values are used for filtering and the grid's layout is persisted. Please remember that an object referenced by the !Key descriptor can only find those objects which are saved in the database. When an object is not saved, it cannot be found by the Session.GetObjectByKey function.