OCI object references in formsgreenspun.com : LUSENET : OCI Best Practices : One Thread
TOCIForm forms have a reference to their "primary" object, and may have references to "secondary" TOCIObject objects as well. The primary object is the object which is edited by the form. Secondary objects are objects which are the source of some data on the form, but are not being edited by the form.
For example, TMiscellaneousForm displays and edits data for a TMiscellaneousObject object. The TMiscellaneousObject is the primary object.
TMiscellaneousForm also displays the names of an employee associated with the miscellaneous file*. This is a secondary object.
These object references are implemented similarly in all forms. For each object reference you will:
- Create a private instance variable used to store the reference to the primary object
- Create a setter procedure used to assign a value to the private instance variable
- Create a property which reads the private instance variable and writes to the setter
The setters for primary and secondary objects are very similar. However, primary object setters must use certain procedure names because those procedures are called by the form ancestor when the user clicks on the "Locked" check box.
A reference to the "primary" object -- this is the object edited by the formprocedure TMiscellaneousIndividualForm.RefreshUI; begin inherited; RefreshDOB; RefreshSSN; RefreshEmployeeID; RefreshNameHistoryCollection; end; procedure TMiscellaneousIndividualForm.RemoveListeners; begin inherited; MiscellaneousIndividualObject.DOB.Broadcaster.RemoveAll(Self); MiscellaneousIndividualObject.SSN.Broadcaster.RemoveAll(Self); MiscellaneousIndividualObject.EmployeeID.Broadcaster.RemoveAll(Self); MiscellaneousIndividualObject.NameHistoryCollection.Broadcaster.RemoveAll(Self); end; procedure TMiscellaneousIndividualForm.AddListeners; begin inherited; MiscellaneousIndividualObject.DOB.Broadcaster.AddListener(DOBListener); MiscellaneousIndividualObject.SSN.Broadcaster.AddListener(SSNListener); MiscellaneousIndividualObject.EmployeeID.Broadcaster.AddListener(EmployeeIDListener); MiscellaneousIndividualObject.NameHistoryCollection.Broadcaster.AddListener(NameHistoryCollectionListener); end; procedure TMiscellaneousIndividualForm.SetMiscellaneousIndividualObject(aMiscellaneousIndividualObject: TMiscellaneousIndividualObject); begin if (aMiscellaneousIndividualObject <> MiscellaneousIndividualObject) then begin if (MiscellaneousIndividualObject <> NIL) then begin // Remove listeners to the object currently being referenced, and // tell the object we're not referencing it anymore. RemoveListeners; MiscellaneousIndividualObject.FreeReference(Self); end; // then begin // Change the reference to the new object FMiscellaneousIndividualObject := aMiscellaneousIndividualObject; if (MiscellaneousIndividualObject <> NIL) then begin // Add listeners to the new object being referenced AddListeners; end; // then begin // Refresh the user interface to reflect the new reference RefreshLocked; // This runs RefreshUI end; // then begin end;
In a nutshell, the setter:
- removes its references to the current object (i.e., it removes listeners to the object and runs FreeReference),
- updates the private instance variable to reference the new object,
- adds listeners to the new object
- and refreshes the user-interface to reflect the change to the new object
This code works when the form is first created because InitializeForm assigns a reference to the object (passed in ID) into the OCI object property. When the form is closed FinalizeForm assigns a NIL to the property, which cleans things up.procedure TMiscellaneousIndividualForm.InitializeForm; begin inherited; MiscellaneousIndividualObject := (TMiscellaneousIndividualObject.CreateReference(Self, ID) as TMiscellaneousIndividualObject); end; procedure TMiscellaneousIndividualForm.FinalizeForm; begin MiscellaneousIndividualObject := NIL; // Reference created in InitializeForm EmployeeObject := NIL; // Reference created in RefreshEmployeeID inherited; end;
A reference to a "secondary" object -- data from the object is shown on the form, but not edited by the form
These setters are structured like those for the primary object. However, insteam of running overridden methods named SetListeners, RemoveListeners, and RefreshUI, you put the related code directly in the setter. In this example, the form displays an employee object's FullName property. Therefore, when the reference to the employee changes the form must remove listeners to the old employee object, add listeners to FullName on the new object, and refresh the user interface.procedure TMiscellaneousIndividualForm.SetEmployeeObject(anEmployeeObject: TEmployeeObject); begin if (anEmployeeObject <> EmployeeObject) then begin if (EmployeeObject <> NIL) then begin // Remove listeners to the object currently being referenced, and // tell the object we're not referencing it anymore. EmployeeObject.FullName.Broadcaster.RemoveAll(Self); EmployeeObject.FreeReference(Self); end; // then begin // Change the reference to the new object FEmployeeObject := anEmployeeObject; if (EmployeeObject <> NIL) then begin // Add listeners to the new object being referenced EmployeeObject.FullName.Broadcaster.AddListener(EmployeeObjectFullNameListener); end; // then begin // Refresh the user interface to reflect the new reference RefreshEmployeeObjectFullName; end; // then begin end; procedure TMiscellaneousIndividualForm.RefreshEmployeeObjectFullName; begin if (EmployeeObject = NIL) then begin EditExaminerLink.Text := '(Unassigned)'; SetAsDeadLink(EditExaminerLink); // Defined in UnitCommonRoutines end // then begin else begin if (ExaminerObject.FullName.Value = '') then EditExaminerLink.Text := '(Blank name)' else EditExaminerLink.Text := ExaminerObject.FullName.Value; SetAsActiveLink(EditExaminerLink); // Defined in UnitCommonRoutines end; // else begin
In this case the object reference is created when the EmployeeID listener is run.procedure TMiscellaneousIndividualForm.RefreshEmployeeID; begin if (MiscellaneousObject.EmployeeID = 0) then EmployeeObject := NIL else EmployeeObject := (TEmployeeObject.CreateReference(Self,ID) as TEmployeeObject); end;
* TMiscellaneousIndividualForm doesn't really have an employee reference -- I'm just saying it does to provide an example.
-- Anonymous, July 14, 1998