Object Neighborhoods
In DataFlex 8.2, we introduced the concept of object neighborhoods. The purpose of this change is to make it easier for objects to communicate with each other. Objects within a neighborhood can talk to other objects within the neighborhood by their simple object name without needing to worry about where those objects are located.
Object neighborhoods make it easier to manage visual objects within views. In a view, visual controls are often nested inside containers for appearance purposes only. As you design an application, you may decide that it looks better to place several objects within dbGroups and that it then looks better to place those groups within a dbContainer3d. The Studio makes it very easy to make these kinds of changes. However, every time you move these objects around and put them in different containers, you change the way those objects are referenced from other objects within the view. This creates the need to generate complex object reference statements, and it may require code changes every time you move objects around. This results in code that looks like this:
Get SortOrder of (oSortOrder(oSortParamsGroup(oSetUpContainer(oTabPageReport(oTabDialog(self)))))) to iOrder
If you decide to move your oSortOrder object somewhere else in the view, you need to start all over.
With neighborhoods, all objects in the view are registered with the view, and all objects within the view are visible to all other objects within the view. The same object placed anywhere within the view is now coded as:
Get SortOrder of oSortOrder to iOrder
Views and modal panels are defined as public neighborhoods. You should be able to use object neighborhoods in your views immediately. Old-style object syntax will work as it always did. You can start using the new neighborhood syntax in your views, and it should just work. If you have duplicate object names within your view, your program will still run – you will just have to resolve the object's location the way you always have (the hard way). If, for some reason, you are having problems with neighborhoods, they can be disabled in the view by setting one property.
Object neighborhoods "flatten" the object structure of visual controls, making it possible for all visible controls to see each other. As you will see, objects will still properly encapsulate (hide) non-visual and class-based objects that are clearly not meant to be public. This allows easy access to the objects you want easy access to while still writing properly encapsulated applications.
Expected Use of Neighborhoods
All views and modal dialogs are now defined as being public neighborhoods. All visual objects within this view and any non-visual object created directly within the view or any container will be members of the neighborhood. They can all be accessed from any other object by their short object name.
All views and modal dialogs contain a property named peNeighborhood, which is exposed in the Studio. If you wish to make your view private, you can change the value of peNeighborhood from nhPublic to nhPrivate. Making a view private will make it act exactly as it did prior to DataFlex 8.2. We do not expect you will ever want to change this.
The peNeighborhood property is supported in all objects. We only expose this property in the Studio for view and modal panel objects, as we do not expect you to ever need to change this anywhere else.
Some Examples
Object neighborhoods are designed to be used with the new easy object access referencing. When used together, programs become much easier to code and even easier to read. A few examples should make this point.
// OLD
Get select_state of (oCheckBox1(oGroup1(oContainer1(self)))) to bChecked
Get Value of (oMyGrid(oGroup1(oContainer1(self))) 7 to sVal
Move (Value(oMyGrid(oGroup1(oContainer1(self))), 7) to sVal
// NEW
Get select_state of oCheckBox1 to bChecked
Get Value of oMyGrid 7 to sVal
Move (Value(oMyGrid, 7)) to sVal
// OLD
Procedure OnClick
Set Value of (oCalculate(oMathWizard(self))) to (Value(Customer_number(Address_Tp(CustTD(self))), 0) + "*" + Value(Customer_number(Address_Tp(Customer_zip(self))), 0))
Send DoTheMath of oMathWizard
End_Procedure // OnClick
// NEW
Procedure OnClick
Set Value of oCalculate to (Value(Customer_number) + "*" + Value(Customer_zip))
Send DoTheMath of oMathWizard
End_Procedure // OnClick
How Neighborhood Object Referencing Works
When an object is created, it will try to register itself with a neighborhood. It does this by checking with its parent object by looking at the parent property peNeighborhood. That property will either define the parent as being a neighborhood object (nhPublic or nhPrivate) or it will tell the object to delegate and check with its parent (nhNo). This process will continue until a neighborhood object is encountered. Once found, that neighborhood object will either be public (nhPublic) or private (nhPrivate). If the object is public, it will register this new object as a member of that neighborhood, allowing all other objects in the neighborhood to access it with its short name. If the object is private, the object is not registered. In either case, the search has ended, and the newly created object is either part of a neighborhood or it is not.
This newly created object will have its own peNeighborhood property setting. This does not affect how it is registered, but it does determine how its child objects will be registered when those objects are created. In other words, an object's parent determines its membership in a neighborhood.
Prior to DataFlex 8.2, an object name is found using the following rules:
Send Message of oName
- First, check to see if
oNameis a child object. If found, use that object. - Delegate and see if
oNameis a child of the parent object. If found, use that object. - Continue step 2 until there are no more parent objects, in which case issue an object not found error.
With object neighborhoods, this is now changed as follows (new steps are in italics):
- First, check to see if
oNameis a child object. If found, use that object. - Check if the object is a public neighborhood. If so, mark as "neighborhood found" and see if the object is in the neighbor list. If found, use that object.
- Delegate and see if
oNameis a child of the parent object. If found, use that object. - If a neighborhood has not yet been found, check if the object is a public or private neighborhood. If so, mark as "neighborhood found." If public, see if the object is in the neighbor list. If found, use that object.
- Continue step 3 until there are no more parent objects, in which case issue an object not found error.
These two processes and their order of search are the same except that, when encountered, a check will be made of a public neighborhood for the object name. Only one public neighborhood is ever checked. This means that any object may only belong to one neighborhood. (Supporting membership in multiple nested neighborhoods would only create confusion.)
Neighborhood Behavior and the peNeighborhood Property
As indicated, all neighborhood behavior is controlled by the peNeighborhood property. All objects support this property. Three modes are supported:
-
nhPrivate – If an object is private, it means that all descendant objects (all objects within this object) do not support neighborhood referencing. You can think of these descendant objects as not being part of any neighborhood, or you can think of them as being part of a private neighborhood where they just don't like to talk to each other. This mode makes objects behave exactly the way they did prior to 8.2. Normal object access methods are still used (check if name exists as a child, if not delegate to parent and repeat search). The actual object marked as
nhPrivatemay be part of a neighborhood, but its descendants are not. An object's neighborhood status is determined by its parent. Most objects in DataFlex are private. All visual controls (e.g., form, dbForm) and all non-visual objects (e.g., Array, XML objects) are private. In addition, objects created as part of class construction are usually private. -
nhPublic – If an object is public, it maintains a list of all of its descendants. When an object name is requested of this object, either directly or via object access name delegation, it will search its list to see if the object exists. Views and modal panels are defined as being public. Using this value defines a neighborhood.
-
nhNo – This mode indicates that this object does not define a neighborhood, either public or private. Instead, it allows its descendants (all objects within this object) to ignore this object and check with its parent to see what its neighborhood status might be. This is the mode that is used by visual containers like groups and
container3d. It is the mode that flattens the object structure for visual containers.
We don't expect you will ever have to change this property, with perhaps the one exception of changing a view or modal panel from public to private. Even in this case, we would encourage you to research the need for this change and to see if you can change your application to fully support neighborhoods.
Duplicate Object Names and Neighborhoods
Duplicate object names are allowed within a neighborhood, but only one of those names will be found when the neighborhood list is searched. If you are planning on resolving an object name via a neighborhood, you should avoid using duplicate names. Typically, this will not be a problem. When duplicate names are created within a view, the program rarely needs to find those objects by name – otherwise, you would have assigned the object a unique name. Either you are never sending messages to these objects, or you are creating them dynamically, in which case you should be accessing them by their object handle ID and not their name.
Also, note that a number of classes create objects as part of class construction. You would rarely want to make these objects public, and in fact, they will not be made public. If the object is private, these child objects remain private - this encompasses most objects. Only visual containers are non-private, and even in these cases, they actually are marked private until the end of construct_object. In this case, all the children defined during construction (those objects defined within the class) remain private.
dbTabDialogViews and Object Neighborhoods
In dbTabDialogViews, each dbTabView should be thought of and used like a separate dbView. Each dbTabView may contain object names that are duplicated from other dbTabViews in the same dbTabDialogView. Object neighborhoods and short object referencing inside each dbTabView will work as it would in a dbView. To access objects in other dbTabViews, the complete access method should be used instead of the short object reference.