#GPPT Best Practices for Programmatically Updating Fields on Windows

David Meego - Click for blog homepageHere is another simple customization I thought it would be worth publishing because it allows us to discuss some best practices and also show some cool techniques.

I received an email from a user who wanted to use GP Power Tools to replace some VBA (Visual Basic for Applications) code using GP Power Tools. They wanted to update a SOP (Sales Order Processing) Sales Transaction Entry User Defined Field based automatically but the code they had developed was not working.

After reviewing the code that was sent to me, I wanted to bring up some best practices that developers using GP Power Tools should be aware of…

Best Practices

  • The MBS_Set_Window_Value , MBS_Get_Window_Value and MBS_Run_Window_Value helper functions should not be used if the other window is in the same Dexterity dictionary. They are designed to make it easy to work with windows in another Dexterity dictionary. Instead you can just reference the fields with standard Dexterity commands. This makes for simpler and faster code.
  • If you change a field value using Dexterity, you should issue a run script command on the field to get the change script to run. In VBA the change script runs automatically when a change is made to the field, in Dexterity it is two steps which gives the developer more control and options. For example, you can set a field to a value and us the force change command on it to default the field to a value, but still allow the user to change it.
  • Setting a field and running the field change script is similar to replicating a user typing into the field, but is NOT the same as a user typing into the field and pressing tab. If the script uses a old() or diff() function to look at the previous value, it will not work as expected, the old() value will be the same as the current value and the diff() will be zero. Also, the changed flag on the window will not be set to mark the window as “dirty” or changed.
  • If using the set field and run script approach, you might need to use the force changes window command to manually mark the window as changed. If the window is not marked as changed, it might not save the changes you make.
  • It is always best practice run the field change script after setting the value of a field, however not every field has a change script in the original code for the window. Because you are not sure if the script exists or not AND you don’t know if other developers have added triggers against the field, you should run the script just in case.
  • Finally, when Service Based Architecture was added to GP 2015 (v14.0), an undocumented map <value> to <field> command was added to Dexterity. This command replicates a user tabbing into a field and changing the value of the field. The change script will be run automatically when the focus moves off the field either by “mapping” to another field on the same window or by using the Window_PullFocus() command on the window. This method will allow old() and diff() to work and will set the changed flag of the window.

The Problem

The code sent to me was not working because the value being entered the User Defined Field was not being saved when the OK button was “pressed” by calling it with run script.

The reason is that the OK Button script would only save the data if the contents of the window had been changed and code provided was using the set field and run script approach which does not set the changed flag.

The Solution

Adding the force changes window command solved the problem.

Also, using the map command and Window_PullFocus() approach also can solve the problem. The code for this method is shown in primary trigger script but commented out.

Note: The map command does not evaluate expressions for the source value, so you must place the data you want to “type” into a field into a variable. Hence the use of the l_value string variable in the example code (see below).

The Enhancement

Based on all the best practice points above, I wrote a code example where it would update the User Defined 4 field with the first 20 characters of the Customer Name when the name was changed. Everything was working however, whenever the code ran you could see the User Defined Entry window flash open and close.

To resolve this annoying visual aberration an extra trigger was added when the Sales User-Defined Fields Entry window opens to make the window open “hidden” off screen. This trigger used the Open Window Hidden checkbox on the Action tab available for a before the WIN PRE trigger. To control the trigger so that it only hides the window when we are automatically opening and closing it, we are going to use Helper Functions to set, clear and check a Boolean memory variable. A final trigger on closing the Sales Transaction Entry window will remove the memory variable to clean up.

The Code

Below is the code from the primary trigger showing the use of Memory Variables and the two methods of changing the value of the User Defined Field.

in string IN_OldValue;
in string IN_NewValue;
out boolean OUT_Condition;

local string l_value;
local boolean MBS_Memory_Boolean;

OUT_Condition = false;

{ Comment out default to statements and fully qualify fields }
{ if needing access to tables not attached to the form }
default form to SOP_Entry;
default window to SOP_Entry;

if isopen(form SOP_Entry) then

	{ Use Memory Variable to hide User Defined Window }
	MBS_Memory_Boolean = true;
	call with name "MBS_Memory_Set_Boolean" in dictionary 5261, "Hide SOP UDF", MBS_Memory_Boolean;

	run script 'User Defined Button' of window 'SOP_Entry' of form 'SOP_Entry';
	if isopen(form SOP_User_Defined_Field_Entry) then

{		{ Use Map command which behaves like user entering }
		l_value = substring('Customer Name', 1, 20);
		map l_value to 'User Defined 4' of window SOP_User_Defined_Field_Entry of form SOP_User_Defined_Field_Entry;
		Window_PullFocus(window SOP_User_Defined_Field_Entry of form SOP_User_Defined_Field_Entry);
}
		{ Use traditional Dex commands and force changes on window }
		{ There is no field change script on the window, but good practice to run the script }
		'User Defined 4' of window SOP_User_Defined_Field_Entry of form SOP_User_Defined_Field_Entry = substring('Customer Name', 1, 20);
		run script 'User Defined 4' of window SOP_User_Defined_Field_Entry of form SOP_User_Defined_Field_Entry;
		force changes window SOP_User_Defined_Field_Entry of form SOP_User_Defined_Field_Entry;

		{ Close window }
		run script 'OK Button ' of window SOP_User_Defined_Field_Entry of form SOP_User_Defined_Field_Entry;
	end if;

	{ Use Memory Variable to hide User Defined Window }
	MBS_Memory_Boolean = false;
	call with name "MBS_Memory_Set_Boolean" in dictionary 5261, "Hide SOP UDF", MBS_Memory_Boolean;

	OUT_Condition = true;
end if;

The Project

Below is a screenshot of the Project with the three triggers.

Download the example code, import using the Configuration Export/Import window:

Installing the sample code:

  • If this is the first time importing the project use the Configuration Export/Import window (GP Power Tools >> Routines >> Configuration Export/Import). Select the file and click Import. Then click OK on the confirmation window.
  • If the project already exists, use the Project Setup window instead. Select the file and click Import. Then click OK on the confirmation window.
  • The code will be active on next login or after switching companies, or you can use start them manually from the Project Setup window.

More Information

For more information see

Hope you find this article with its best practices and techniques to hide windows while opening and closing them automatically useful.

David

This article was originally posted on http://www.winthropdc.com/blog.

Please post feedback or comments

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.