The rules for creating a view are actually quite simple. Create a container client. Inside the container object, place all of your data-dictionary objects (DDOs). The DDOs must be placed side by side (as siblings of each other) and properly connected to each other with set ddo_server message. Place your data-entry objects (DEOs) below your DDOs. The DEOs should be nested according to navigational needs. At least one of the DDOs must be assigned to at least one of the DEOs with the set server message, and one of the assigned DDOs should be identified as the view’s main DDO. That's it.
A view must be fully encapsulated. This means that the entire view must be contained inside a single object. The container object should be based on the dbView class. The external program will communicate with this view by sending messages to this dbView object.
Views are activated by sending a special message to the view’s parent object. This message must be created along with the view. A special command, Activate_view (and, optionally, Deferred_view ) is used to create this method. By convention the name of this message should be the name of object, preceded with "activate_" (e.g., the view oCustomer would have an access method of Activate_oCustomer). This might be the only external access method to this object.
As stated, a view contains a group of connected data-dictionary objects. Before you create the data dictionary objects, you must first create the data-dictionary classes. Using the Database Builder utility you can very easily create data dictionary subclass for each data table in your database. These classes will be based on the DataDictionary class. These classes contain all of your special database rules.
Each data-dictionary subclasses will be placed in its own own package file(s). The conventional file extension for data-dictionary-subclass packages is ".dd". Any component that needs to use a particular data table and the database rules that are represented in its data dictionary class, may simply use the package file that contains it.
A single program will often have multiple views that contain DDOs that access the same data file and therefore are based on the same data-dictionary subclass. Because these DDOs will reside in different views, they are each encapsulated by their respective container object, and no conflict will occur among them, even if they have the same name.
There are explicit rules for placing DDOs in a view client. These are:
All DDOs are based on specialized data-dictionary subclasses, each created for a particular data table.
All the DDOs of a view are placed inside the view client as sibling objects. The parent-table DDOs are created first, then the child-table DDOs.
Parent/child relationships are established in DDOs by setting the DDO_server property in the child-table object. The link between a parent and child is established by the child DDO updating the parent DDO. This link must be established and it must be correct.
Within your view, you should identify define a main DDO. This is done by setting the view property Main_DD . The main DDO is usually that of the file that the view is centered around. In simple views, this will often be the child-most table’s DDO. In more-complex views, this may not be the case. In an order-entry view, the order-header DDO would be the main DD (even though there is a child-table order-detail DDO).
All objects referenced in the DDO_server property (there can be, and often are, more than one) and the Main_DD property (only one of these, ever) are referenced using the standard object name access syntax (e.g. set DDO_server to oCustomer_dd).
Depending on the requirements of your view, you may need to provide a relates-to constraint between a child and parent DDO. This is done with by placing the statement set constrain_file to parent_file inside of the DDO object. The constraint link must be made in addition to the DDO_Server link. (They are separate links). As a general rule, do not create a relates-to constraint unless it is truly needed.
When you create and connect DDOs in a view, you are creating a data-dictionary structure. The DDOs will all act in a coordinated fashion—this is what you want. A data-dictionary structure must be encapsulated inside the view. You would never connect two DDOs across two views.
Placing your objects in a view is easy. Care must be taken to make sure that the updating links are properly established. The following diagram provides an example of a database structure, a visual representation of the data-server structure (and linking) and a sample of how this structure is coded.
Object View_Object is a dbView
Object Customer_DD is a Customer_DataDictionary
End_Object
Object Terms_DD is a Terms_DataDictionary
End_Object
Object Vendor_DD is a Vendor_DataDictionary
End_Object
Object Orders_DD is an Orders_DataDictionary
set ddo_server to Customer_DD
set ddo_server to Terms_DD
End_Object
Object Inventory_DD is an Inventory_DataDictionary
set ddo_server to Vendor_DD
End_Object
Object OrderDtl_DD is an OrderDtl_DataDictionary
set ddo_server to Orders_DD
set ddo_server to Inventory_DD
set constrain_file to Orders.File_number
End_Object
:
Your data-entry objects are placed below your DDOs in the view. The DEOs are created with the following rules:
There are two types of DEOs: Controls and Containers. The Controls are used to display and edit data. Examples of controls are single line edits (dbForm), multi-line edits (dbEdit), checkboxes (dbCheckbox) and grids (dbGrid). Containers are used to visually group controls and container. Examples of containers are groups (dbGroup) and tab-dialogs (dbTabDialog).
Container DEOs may contain control DEOs and other Container DEO. This is referred to as nesting of DEOs. Nesting DEOs has no effect on database behaviors (saving, deleting, clearing, finding). You choose to nest or not to nest DEOs based solely on visual requirements and required navigational behaviors. You never place DEOs inside of DDOs.
DEOs must be connected to DDOs by setting the server property. The DDO that you connect to determines the DEO's saving, clearing, finding and deleting behaviors.
All DDOs set in the server property are referenced with the standard object access syntax (e.g. Set Server to Customer_dd).
DEOs should only use DDOs that are contained inside the same view.
In some cases, all DEOs will connect to a single DDO (although this DDO will often connect to other DDOs). In other cases, different DEOs within a view will use different DDOs. An order entry view will have its header DEOs using a header DDO and the line-detail DEOs using a detail DDO. In all cases, DEOs only use DDOs that are internal to the current view.
Although there are several ways to access an object in DataFlex, the Framework is designed to use only one method for referencing an object – you simply refer to the object. This is referred to as the standard object access syntax. For example:
Set Server to Customer_dd
Get Value of oCustomerState to sState
Send UpdateValue of oMyHelper sParam1
Send Message of object_name {param1 .. param_n}
Get Message of object_name {param_1 .. param_n} to ReturnValue
Set Message of object_name to ParamValue
Basically, this method says "Find an object named object_name that is a child of the current-object (the current-object is the object sending the message). If the child object is found, the message is sent to this object. If this were all this could do, it would be a limited method for accessing objects. Delegation, however, makes this an extremely powerful object-access method.
If object_name is not found among the children of the current object, the message gets delegated to the current object’s parent object. The parent object then looks for an object named object_name among its child objects. At this point, object_name might be found among siblings of the original current object. If not, delegation occurs again, and the siblings of the parent object are reviewed. Understanding the role delegation plays here is crucial.
All objects are accessed using the standard object access syntax. This provides access to child objects, sibling objects, and sibling-of-parent objects on up the object tree. Other ways of referencing objects are never used.
If an object cannot be accessed using this access syntax, you should not be accessing it from where you are trying to. For example, a parent object should not directly communicate with a grandchild object. The principle of encapsulation and this access method discourages this. (An exception to this rule, the use of object neighborhoods, will be discussed later.)
Earlier versions of DataFlex required slightly more complex syntax for standard object access where the object name needed to be part of an expression. Examples of this syntax are Send MyMessage of (oMyObject(self)) and Send MyMessage of (oMyObject(current_object)). This more complicated syntax is not required and can be replaced with the recommended and simpler Send MyMessage of oMyObject.
This can all be summarized in the following way. An object view consists of a dbView, which encapsulates all DDOs and DEOs. All DDOs are placed as sibling objects inside the container. They are connected to each other with the set DDO_Server message. DEOs are placed underneath the DDOs and are nested (or not nested) according to navigational needs. The DEOs are connected to the data-server structure with the server property. Because views completely encapsulate their DDOs and their DEOs, they are independent stand-alone units. A view can be added to any program without fear of this new view creating side effects in other parts of the program.
Views should be created inside their own package files. In addition to the view object, this package should use still other package files and incorporate a view-access method into the view. The following example shows what a simple Studio generated view-object package looks like:
Use dfClient.pkg
Use DataDict.pkg
Use dfEntry.pkg
Use dfCEntry.pkg
Use Vendor.DD
DEFERRED_VIEW Activate_oVendorView FOR ;
;
Object oVendorView is a dbView
Set Border_Style to Border_Thick
Set Label to "Vendor Entry View"
Set Location to 6 6
Set Size to 137 281
Set piMaxSize to 137 350
Set piMinSize to 137 215
Object Vendor_DD is a Vendor_DataDictionary
End_Object // Vendor_DD
Set Main_DD to Vendor_DD
Set Server to Vendor_DD
Object oContainer1 is a dbContainer3d
Set Size to 129 273
Set Location to 4 4
Set peAnchors to anAll
Object oVendor_Id is a dbForm
Entry_Item Vendor.ID
Set Label to "Vendor ID:"
Set Size to 13 42
Set Location to 4 67
Set peAnchors to anTopLeft
Set Label_Col_Offset to 2
Set Label_Justification_Mode to jMode_Right
End_Object // oVendor_ID
Object oVendor_Name is a dbForm
Entry_Item Vendor.Name
Set Label to "Vendor Name:"
Set Size to 13 186
Set Location to 18 67
Set peAnchors to anTopLeftRight
Set Label_Col_Offset to 2
Set Label_Justification_Mode to jMode_Right
End_Object // oVendor_Name
Object oVendor_Address is a dbForm
Entry_Item Vendor.Address
Set Label to "Street Address:"
Set Size to 13 186
Set Location to 34 67
Set peAnchors to anTopLeftRight
Set Label_Col_Offset to 2
Set Label_Justification_Mode to jMode_Right
End_Object // oVendor_Address
Object oVendor_City is a dbForm
Entry_Item Vendor.City
Set Label to "City:"
Set Size to 13 90
Set Location to 49 67
Set peAnchors to anTopLeft
Set Label_Col_Offset to 2
Set Label_Justification_Mode to jMode_Right
End_Object // oVendor_City
Object oVendor_State is a dbComboForm
Entry_Item Vendor.State
Set Label to "State:"
Set Size to 13 32
Set Location to 64 67
Set peAnchors to anTopLeft
Set Form_Border to 0
Set Label_Col_Offset to 2
Set Label_Justification_Mode to jMode_Right
Set Entry_State to False
Set Code_Display_Mode to cb_code_display_code
End_Object // oVendor_State
Object oVendor_Zip is a dbForm
Entry_Item Vendor.Zip
Set Label to "Zip/Postal Code:"
Set Size to 13 66
Set Location to 79 67
Set peAnchors to anTopLeft
Set Label_Col_Offset to 2
Set Label_Justification_Mode to jMode_Right
End_Object // oVendor_Zip
Object oVendor_Phone_Number is a dbForm
Entry_Item Vendor.Phone_Number
Set Label to "Phone Number:"
Set Size to 13 126
Set Location to 94 67
Set peAnchors to anTopLeftRight
Set Label_Col_Offset to 2
Set Label_Justification_Mode to jMode_Right
End_Object // oVendor_Phone_Number
Object oVendor_Fax_Number is a dbForm
Entry_Item Vendor.Fax_Number
Set Label to "Fax Number:"
Set Size to 13 126
Set Location to 108 67
Set peAnchors to anTopLeftRight
Set Label_Col_Offset to 2
Set Label_Justification_Mode to jMode_Right
End_Object // oVendor_Fax_Number
End_Object // oContainer1
CD_End_Object // oVendorView
This is a complete view package. Notable elements are:
Use DFAllent.pkg, which is the package that allows your program to use the standard data-entry classes as well as other features required in most data-entry programs. This includes all of the high-level classes.
Use Vendor.dd, the data-dictionary-subclass package. Using DataBase Builder, you will have created a data-dictionary subclass for this data file. The Vendor_DataDictionary class is contained in this class package. This package also opens the data files. This view needs and uses the one DD class for the vendor table.
Deferred_view activate_oVendorView for; creates the view-access Message activate_oVendorView, which will activate the oVendorView dbView object. This message will be used by your main program in the view pulldown to activate the view. This can be sent from any object.
Object oVendorView is a dbView creates the actual view object, a dbView. It contains a properly connected data-dictionary structure and data-entry objects. In this case, all DEOs are using the same DDO, so the server is set only once.