This page documents all the properties and methods on the Dynamic Form and Dynamic Form Render Engine classes.

Note: The DynamicForm class uses an instance of the DynamicFormRenderEngine class to do all the real work behind the scenes.

Most basic usage of a Dynamic Form can be accomplished by working on properties and methods on the DynamicForm instance which you create at run time. However, some of the more detailed or advanced settings must be accessed though the oRenderEngine object that lives on the DynamicForm instance. This oRenderEngine object is created automaticllay by the DynamicForm instance when it it created, so it will be alive and ready to respond to your settings as you make them. You access the oRenderEngine object as follows: loForm.oRenderEngine

Note: Many of the properties defined on the form are merely wrappers which will eventually be passed on to the RenderEngine class. They are hosted on the form simply as a convenience for coding.

DynamicForm Class – Properties

Property name Default value Description
cAlias (empty) (Optional) The cursor/alias to which the controlsources in the cBodyMarkup will be bound. Make sure this alias is opened and positioned at this correct record. Note: If you need to bind form fields to more than one cursor, simply include the cursor/alias in the controlsource markup along with the field name. I.e. “MyTable1.field1 | MyTable2.Field1”  (See Step 1 on main page)
oDataObject .NULL. (Optional) Build or populate an object with data properties, then pass it in to this oDataObject property. The controlsource for each field in the cBodyMarkup will now bind to this oDataObject. (See Step 1 on main page)
oBusinessObject .NULL. (Optional) A Business Object that has a data access methods which can be called to save the changes to the oDataObject.
See Using Dynamic Forms with Business Objects.
cBusinessObjectSaveMethod (empty) (Optional) A string indicating the method and any parameters that are to be called on oBusinessObject to save the oDataObject when the user clicks the Save button.
See Using Dynamic Forms with Business Objects.
cHeading (empty) (Optional) The label caption to be used in the Header area.
nHeadingFontSize 14 The fontsize for the label in the Header area.
cSaveButtonCaption .NULL. The caption to be displayed in the Save button in the footer area.
cCancelButtonCaption .NULL. The caption to be displayed in the Cancel button in the footer area.
cHeaderMarkup (see desc) The markup syntax used to render the Header area. See Header/Body/Footer Diagram for more info and default layout.
cBodyMarkup   The markup syntax used to render the main Body area. See Header/Body/Footer Diagram for more info.
cFooterMarkup (see desc) The markup syntax used to render the Footer area. See Header/Body/Footer Diagram for more info and default layout.
cReturn  

You can get custom return values from the Dynamic Form using instances of the default “commandbutton” class, which resolves to the custom DF_ResultButton class by default. Using these command buttons, when the button is clicked, the form will hide and the caption of the command button will be passed to the loForm.cReturn property (any hotkey characters in the caption will be removed). This allows you to easily test loForm.cReturn to see which of command button was clicked, and you can take the appropriate action as control passes back to the calling program.

Actually, the button Caption is passed to the Tag property on the button, and the button click event passes its Tag value back to loForm.cResult and then hides the form. So, if needed, you can set the Tag value directly if you do not want to use the caption as the return value.

See Step 7 on main page for more info.

lRestoreDataOnCancel .T. When .T., changes to all controlsource data bindings will be restored to their original values if form Cancelled by user. This applies to cAlias fields, oDataObjectProperties, and private/public variables, as well as any other directly referenced aliases via the controlsource.
See the aBackup[] array property on the Render Engine class for where these values are stored, and see BackupData() and RestoreData() on the Render Engine class.
lClearEventsOnClose .F. In case want Dynamic Form to call Clear Events when the form is closed via Save, Cancel, or the [X] close button.
lSaveClicked .F. Indicates if the Save button was clicked by the user. (See Step 7 on main page)
lCancelClicked .F. Indicates if the Cancel button was clicked by the user. (See Step 7 on main page)
oRenderEngine   The form class will create and use an instance of the DynamicFormRenderEngine class to do all the rendering work. The RenderEngine object is stored in this oRenderEngine property.  If you wish to override any of the DynamicFormRenderEngine poperties or methods, you can do so by following the instructions in Subclassing DynamicForm.

DynamicForm Class – Methods

Method Name Parameters Description
Render() (none) It is not necessary to call this method, as you can call the Show() method directly to display the form immediately. However, this method can be used to pre-render the controls into the form’s container in order to check for rendering or binding errors before attempting to display the form. This method returns a Boolean value indicating if the render process completed without errors. This method can be used when you want to pre-render the form to check for errors before calling the Show() method. The form is not displayed until *you* call the Show() method.

Any rendering errors are usually caused by errors in your cBodyMarkup markup string.

Rendering Errors - If the Render() methods returns .F., this means there were rendering errors, which you can read from loForm.oRenderEngine.nErrorCount and you can get and error list in a string format by calling loForm.oRenderEngine.GetErrorsAsString(), or get details on every error from the loForm.oRenderEngine.oErrors collection. Learn more about rendering errors here.

Even with rendering errors, the form can still be displayed to the user if desired. During development, showing the form (even with errors) will help you see where the errors occurred, as it will show a red error container in place of any controls which had rendering errors.

Show() tnMode, toFormObject

Display the form to the user by calling loForm.Show(). The default mode is a Modal, which can be overridden to Modeless with parameter tnMode.

Modal forms – After calling Show() or Show(1) a Modal form will be presented to the user. When they click Save, Cancel, or the [X] button the Dynamic Form will be hidden and flow will return to the calling program where you can then read any property on loForm and loForm.oRenderEngine, and even access the rendered controls. Note: at this point the form is hidden only, but still alive and accessible via its object reference. So, after control has passed back to the calling program code, you can perform the next steps required based on your application architecture... First, analyze the loForm.cResult value to know which button was clicked, then, for example,  perform any data validation, deal with buffered cursors, or call the “save” method on a Business Object.

Modeless forms – When calling Show(0) to create a Modeless form, Dynamic Form will add a unique global reference to itself on _screen (I.e. _screen.DF_3LW0JDOD6) so that the form will be kept alive even after control has passed back to the calling code and the local form reference eventually falls out of scope. From here your Dynamic Form will be released only when the user clicks the Save or Cancel button. When released, the global reference will be removed from _screen and form object will be cleared from memory. You may want to trap the Save or Cancel user actions by use of BindEvent(). You can bind to loForm.Save() and loForm.Cancel() for this purpose. The methods perform no local actions, and are merely provided as hook points for BindEvent() as described here.

Note, since the form is Modeless, if it is bound to a cursor, any movement in the record pointer in the underlying cursor will result in a change of data on the form. The could be a desirable or undesirable affect, and this behavior is exactly the same as with regular FoxPro modeless forms. So, your handling of record pointers and data management is something you must manage, just like you do in regular modeless forms.

Handling Save and Cancel Buttons– The Save and Cancel buttons will trigger calls to the Save() and Cancel() methods on the form. This architecture allows you subclass DynamicForm to provide your own Save() and Cancel() code, or to hook into these events with a BindEvent() call, if desired,  to respond to these  user actions when they eventually occur. After triggering the Save() or Cancel() methods on the form, the buttons will Hide the form if it is Modal (see Modal Forms section above), or Release the form if it is Modeless (see Modeless Forms section above).

Saving changes

If your fields are bound to cursors, the changes are applied in real time as the user edits the data on the form. If you cursors use Table Buffering, *you* will have to handle the TableUpdate() or TableRevert() calls in your handling of the Save() and Cancel() clicks as described above.

If your forms are bound to data objects you can process the changes according to your normal practices once flow returns to your calling code.  See the sample code at the top of the source code prg for an example of this pattern, and Step 7 on the main page.

Business Objects - If your forms are bound to data objects and have supporting Business Objects which provide data handling methods, you can wire up the Save button on your Dynamic Form to the “save” method on the Business Object by using the corresponding properties on the Render Engine to implement this functionality. See Using Dynamic Forms with Business Objects for more details.

 

Parameters:

tnMode -    0 = Modeless,   1 = Modal (default)

toFormObject –  You can have the rendered Dynamic Form centered in a hosting form if you pass in a reference to the hosting form when calling the Show() method on Dynamic Form:


To center the form relative to another other form:

loForm.Show(1, loSomeFormRef)


To assign a specific position:

loForm.Show(1, “100, 200”)

Notice the second parameter is a *string* with a “Top, Left” position value. This equates to loForm.Top = 100 and loForm.Left = 200.  The Height and Width of the form will be determined by the final rendered size, as always.


Another option is to Assign your own position using loForm.Left and loForm.Top, and then tell Dynamic Form not to touch it:

loForm.Show(1, .F.)

     

DynamicFormRenderEngine class – Properties

These properties control the visual layout and rendering flow that happens by the Render Engine.

You access these properties in the following way via the Dynamic Form object:  loForm.oRenderEngine.PropertyName

You can also use the Render Engine class directly to render markup into the object assigned to  the oContainer property or by passing it to the Render(toContainer) method.

Note: It is recommended that you follow the subclassing guidelines to create your own classes for DynamicForm and DynamicFormRenderEngine so that you can easily override any of these default values to suite your own usage and form designs.

Property Name Default Value Description / Notes

cAlias

(empty)

The name of a cursor or alias to which the cBodyMarkup controls are bound.

oDataObject

.NULL.

The object to which the cBodyMarkup controls are bound.

oBusinessObject .NULL. (Optional) A Business Object that has a data access methods which can be called to save the changes to the oDataObject.
See Using Dynamic Forms with Business Objects.
cBusinessObjectSaveMethod (empty) (Optional) A string indicating the method and any parameters that are to be called on oBusinessObject to save the oDataObject.
See Using Dynamic Forms with Business Objects.

cBodyMarkup

.NULL. This is the “markup syntax” string which defines fields, control classes, and other attributes to define the layout of the form.
If cBodyMarkup remains .null. at run time, then all properties from oDataObject or all fields from cAlias will be displayed.
You can specify fields to skip using the cSkipFields property. 
See Markup Syntax guide for details. See Form Layout Diagram for more details.
cHeaderMarkup .NULL. The layout markup for the Header area of the form. If .null. at run time, the default Header markup from GetHeaderMarkup() method will be used. This Header markup is appended to the beginning of cBodyMarkup. The default Header markup includes label and a horizontal line.
You can set this property to your own custom Header markup, or set it to an empty string to omit any Header from the rendered form. See Footer and Header Diagram for more details.
cFooterMarkup .NULL. The layout markup for the Footer area of the form. If .null. at run time, the default Footer markup from GetFooterMarkup() method will be used. This Footer markup is appended to the end of cBodyMarkup. The default Footer markup includes a horizontal line, a Save button and a Cancel button.
You can set this property to your own custom Footer markup, or set it to an empty string to omit any Footer from the rendered form. See Footer and Header Diagram for more details.
cHeading (empty) A string that is used by the cHeaderMarkup layout to set the caption of the form heading label.
nHeadingFontSize 12 The fontsize for the form heading label. Used in the cHeaderMarkup string to size the label.
cSaveButtonCaption .NULL. The caption to be displayed in the Save Button in the footer area.
cCancelButtonCaption .NULL. The caption to be displayed in the Cancel Button in the footer area.
cHeaderMarkup (see desc) This is a Header markup which is appended to the beginning of cBodyMarkup. The default Header markup includes label and a horizontal line. Set to (empty) to omit the Header area from the form, or override to create a custom Header.
cFooterMarkup (see desc) This is a default markup string which is appended to the end of cBodyMarkup to add a horizontal line, a Save and Cancel button to form a “Footer” region on the form.
Set to (empty) to omit the Footer area from the form, or override to create a custom Footer.
cSkipFields (empty) Any fields listed here will be skipped when then form is rendered, even if they are listed in cBodyMarkup. Separate each field in this list with a comma or space.

nControlLeft

(see desc) The .Left position of the first control on a row. Relative to left edge of form or current column.
If lLabelsAbove = .f. (default) , the default nControlLeft value is 120.
If lLabelsAbove  = .t., the default nControlLeft value is 20.

nFirstControlTop

(see desc) The .Top position of the first control on the form, or in the current column.
Default = 10 for lLabelsAbove = .F.
Default = 30 for lLablesAbove =.T.

nVerticalSpacing

(see desc) The vertical spacing between each UI control that has a ControlSource proprty. Note: for control that do not have a ControlSource propert, see nVerticalSpacingNonControlSourceControls .

If lAutoAdjustVerticalPositionAndHeight = .F. (default), this value is the distance from the BOTTOM of the last control to the the .Top of the next control.
  If lLabelsAbove = .F.,  the default value is 15, else the default is 30 (to make room for the label).

If lAutoAdjustVerticalPositionAndHeight = .T., this value is from the .Top of one control to the .Top of the next control.
  If lLabelsAbove = .F., the default value is 30, else the default is 50.
nVerticalSpacingNonControlSourceControls 10 This property controls the vertical spacing used to render controls that do not have a ControlSource property (i.e. label, line), or if the control baseclass is 'checkbox' and uses lLabelsAbove = .t.

These types of controls often do no need or use as much vertical space as, say, a textbox, so it’s often beneficial to set a tighter vertical spacing for these.
lAutoAdjustVerticalPositionAndHeight .F. Forces the .Top and .Height of each control to “snap” to a grid system based on increments on nControlHeight and nVerticalSpacing. The helps keeps control vertically aligned when form spans two columns or more. When enabling this feature, any .Top and .Height values specified in attributes may be adjusted to “snap” to the grid system at its incremental points.

lLabelsAbove

.F. Default position is for labels to be inline with the input control, to its left. Set this property to .T. to have the labels placed ABOVE the input control.
See Field Labels link for more info.

nCheckBoxAlignment

0

0 = Middle Left (Caption on Right) (Default in VFP)
1 = Middle Right (Caption on Left)

nControlHeight 24 The .Height of each control that’s generated. Use :height => ‘n’ to override on any given control.
nHorizontalSpacing 15 Horizontal distance between controls when rendering on the same row with :row=increment => '0'
nHorizontalLabelGap 8 The horizontal spacing between the label and the next input control (when labels are inline with controls).
nColumnWidth 200 The width of each virtual column on the page. See Columns link for more info.
nColumnHeight 800 The host container (a.k.a. “Render surface”) will be resized up to this height before switching to next column
See Columns link for more info, and the Form Layout diagram to understand more about the rendering container.

When the Render() method is called, the caller passes in a container reference in which the caller wants controls to be rendered. As the controls are generated, the RenderEngine automatically increases the Height of the passed container, if necessary, to hold the generated controls. Eventually, this container could get VERY TALL, so as to become unusable or even off-screen. This is where nColumnHeight comes in, which says “grow the passed container up to this height, then move over to the next column”

Or, said another way, “If the contents reach nColumnHeight, then switch over to the next column”

You can avoid the effects of this column-changing behavior simply by setting a really high nColumnHeight in your subclass.

oContainer .null. The container into which controls from the markup will be rendered. This can also be set when passed into the Render() method.

These properties control default height and width of input controls

The defaults are applied based on the baseclasses.
Property Name Default Value Description / Notes

nControlHeight

24

The .Height of each control. Use :height => ‘n’ to override.

nTextBoxWidth

100

Default width of textboxes. Use :width => 'n' to override.

nEditBoxWidth

200

Default width of editboxes. Use :width => 'n' to override.

nNumericFieldTextboxWidth

100

Data types of Numeric will be displayed in a textbox of this width
Use :width => 'n' to override.

nCheckBoxWidth

100

Default width of checkbox. Use :width => 'n' to override.

nControlWidth

100

Default width for any other controls besides the specific ones above.
Use :width => 'n' to override.

Advanced Properties

Property Name Default Value Description / Notes

cDelimiterPattern

‘|’

Caution: Don't use a comma as delimiter. It will likely break things. Default is (pipe symbol).

cAttributeNameDelimiterPattern ‘.’ The delimiter pattern used to denote the beginning of an attribute name. Default is dot (.).
cAttributeValueDelimiterPattern ‘=’ The delimiter pattern used to denote the beginning of an attribute value. Default is equal sign (=).
oContainer .NULL. When calling the Render() method, you pass in an object reference to a container into which you want the controls rendered. This object reference will be stored locally on the RenderEngine in this property.

cDataObjectRef

(empty) The reference to the oDataObject to be used in the ControlSource property of each control that gets generated.
I.e. 'Thisform.oBusObj.oData' any object with Private or Public scope.
nErrorCount 0 The number of errors encountered by the RenderingEngine when reading and applying the markup syntax.
oErrors .NULL. A collection of error messages encountered by the RenderingEngine when reading and applying the markup syntax.
You can get this collection returned as a string list by calling the GetErrorsAsString() method.
aBackup .F. An array which holds the controlsource names from cBodyMarkup and the initial values at render time. This is used as a backup of the initial values so they can later be restored by RestoreData(), if required. See restoring data values for more info.

DynamicFormRenderEngine class - Methods

You can access these methods in the following way from a Dynamic Form instance: loForm.oRenderEngine.MethodName()

The only Render Engine methods that are generally called from the outside are:

Method Name Parameters Description / Notes

Render()

toContainer

This method processes the cBodyMarkup string to create the individual controls within the passed toContainer. If no container is passed in, it will pull from the oContainer property on the class. If toContainer is passed here, the oContainer property on the class will be assigned to this object.

RestoreData()

none Restores the controlsource bindings to their original data values.  See restoring data values for more info.

GetErrorsAsString()

none

Returns a string value of any rendering error messages that were triggered during the Render() process. Learn more about rendering errors here.

GetHeaderMarkup() none A method that returns the cHeaderMarkup string to create the “Header” region of the form.
GetFooterMarkup() none A method that returns the cFooterMarkup string to create the “Footer” region of the form.

Here is a complete list of methods on the DynamicFormRenderEngine class. Most of these methods should be regarded as internal methods, and are not needed externally during regular use.

While most of the rendered layout is controlled by class properties which you can adjust as desired, if you really want to dig deep into the rendering logic to make lower level changes in the layout flow, you could subclass the the DynamicFormRenderEngine and override any of the styling/flow/render-logic methods to suite your particular needs or tastes. Go for it!!

 

image

Last edited Sep 30, 2014 at 4:16 AM by mattslay, version 58

Comments

No comments yet.