#MSDynGP Development: Driving the User Interface of Microsoft Dynamics GP using Code

David Meego - Click for blog homepageOver the last couple of months I have been seeing a huge uptake on the sale and use of GP Power Tools – Development Tools module as more and more Microsoft Dynamics GP customer sites move their customizations away for the now “End of Life” Visual Basic for Applications (VBA).

This article explains some of the differences and techniques for the common method driving the user interface using code written in VBA, Dexterity and Visual Studio Tools (C# or Visual Basic .Net).

The two most common “user actions” that you would want to replicate are clicking a push button and changing a window field. The methods to perform these actions varies depending on the language used, so below are the examples using the Sales Transaction Entry window Batch Number field and expansion button.

Introduction

Keep in mind that the native development environment for Microsoft Dynamics GP is Dexterity (using the sanScript language), so everything in VBA or Visual Studio Tools is actually mapped to Dexterity functionality and features. The terminology might be different, but the underlying functionality is always Dexterity.

Note: Dexterity allows spaces in resource technical names for forms, windows and fields. While forms and windows usually do not have spaces in their names, it is very common for fields to have spaces. If a resource has a space in its name, it must be enclosed in single quotes. Best practice is to always enclose window fields in single quotes (even when there are no spaces) as this makes it much easier to tell the difference between a window field and a script variable or parameter.

The examples below show fully qualified names where the form and window names are included so you can see the syntax differences.

Note: Dexterity uses the resource Technical Names to address forms, windows and fields. VBA uses Display Names with the spaces stripped or the field’s linked prompt with spaces stripped. VBA names can be edited by changing the properties for the resource if needed. Visual Studio Tools (C# and VB.Net) uses the Technical Names with spaces stripped in “CamelCase”.

Local fields are fields defined on a particular Dexterity form and are not available for use in tables or other forms. In Dexterity they are prefixed with (L) and a space and so will always need to be in single quotes. In Visual Studio (C# and VB.Net) they are prefixed with the word Local followed by the field name.

Clicking a Push Button

The code for a push button is contained in the field change script and can be executed by forcing that script to run.

Visual Basic for Applications (VBA)

SalesTransactionEntry.ExpansionButton3 = 1

Dexterity (sanScript)

run script 'Expansion Button 3' of window SOP_Entry of form SOP_Entry;

Visual Studio Tools (C#)

Dynamics.Forms.SopEntry.SopEntry.ExpansionButton3.RunValidate();

Visual Studio Tools (VB.Net)

Dynamics.Forms.SopEntry.SopEntry.ExpansionButton3.RunValidate()

Changing a Field Value (No User Interaction)

The code for the for a field is usually fully contained in the field’s change script, but sometimes there might also be code in the field’s pre script or post scripts that needs to also be executed. There also might be calls to the Dexterity old() and diff() functions in the change script that might need different techniques, more on this later.

This first two sets of examples is just handling the simplest situation where there is only a change script that does not use old() or diff() functions.

Note: In VBA when a field’s value is changed, the change script is automatically executed. In Dexterity and Visual Studio Tools, the change script has to be executed as a separate step which gives the developer more control than the simplified VBA approach.

Visual Basic for Applications (VBA)

SalesTransactionEntry.BatchID = "TEST"

Dexterity (sanScript)

'Batch Number' of window SOP_Entry of form SOP_Entry = "Test";
run script 'Batch Number' of window SOP_Entry of form SOP_Entry;

Visual Studio Tools (C#)

Dynamics.Forms.SopEntry.SopEntry.BatchNumber.Value = "Test";
Dynamics.Forms.SopEntry.SopEntry.BatchNumber.RunValidate();

Visual Studio Tools (VB.Net)

Dynamics.Forms.SopEntry.SopEntry.BatchNumber.Value = "Test"
Dynamics.Forms.SopEntry.SopEntry.BatchNumber.RunValidate()

Defaulting a Field Value (For user to change or accept)

There might be times where you want to put a default value into a field and then wait for the user to either accept the value by just tabbing off or maybe change the value before tabbing off. This technique is very commonly used for the next transaction numbers in Microsoft Dynamics GP.

These commands should be the last code in your script so that the focus is left on the field waiting for the user’s next action.  The force change or ForceValidate() command ensures that the change script is executed even if the user makes no changes and just tabs off.

Visual Basic for Applications (VBA)

' Not possible in VBA because you cannot change a 
' field value without running the change script

Dexterity (sanScript)

'Batch Number' of window SOP_Entry of form SOP_Entry = "Test";
force change 'Batch Number' of window SOP_Entry of form SOP_Entry;
focus 'Batch Number' of window SOP_Entry of form SOP_Entry;

Visual Studio Tools (C#)

Dynamics.Forms.SopEntry.SopEntry.BatchNumber.Value = "Test";
Dynamics.Forms.SopEntry.SopEntry.BatchNumber.ForceValidate(true);
Dynamics.Forms.SopEntry.SopEntry.BatchNumber.Focus();

Visual Studio Tools (VB.Net)

Dynamics.Forms.SopEntry.SopEntry.BatchNumber.Value = "Test"
Dynamics.Forms.SopEntry.SopEntry.BatchNumber.ForceValidate(True)
Dynamics.Forms.SopEntry.SopEntry.BatchNumber.Focus()

What to do if old() or diff() functions are used

Dexterity has two functions that can be used in change scripts which allow you to reference the previous value of a field and with numeric fields the difference between the current and previous values. When the user is moving around a window they work perfectly, but when driving the user interface via code, they usually fail to work correctly.

The reason is that they work by storing the previous value away internally when the field gains focus and if no previous value has been stored, they will use the current value. This means old() returns the current value and diff() returns 0. If the code is looking for old() <> ‘Current Value’ or diff() <> 0, it will fail to make the updates needed and appear not to work or not work correctly (such as total not being updated).

The Dexterity focus command does not help much here as it only takes effect after all the code has executed. A way around this was using the run script delayed command to restart your custom code after the previous script has completed, but this required a extra field added to the window with either code added to it, or a trigger registered against it. Very messy and complex. There is an undocumented Dexterity function library Window_SetFocus()command which will move the focus immediately.

So there are some alternate techniques that can be used to handle these situations better by moving the focus to the field before making a change to the value.

Visual Basic for Applications (VBA)

SalesTransactionEntry.BatchID.Focus("TEST")

Dexterity (sanScript)

Window_SetFocus('Batch Number' of window SOP_Entry of form SOP_Entry);
'Batch Number' of window SOP_Entry of form SOP_Entry = "Test";
run script 'Batch Number' of window SOP_Entry of form SOP_Entry;

Visual Studio Tools (C#)

Dynamics.Forms.SopEntry.SopEntry.BatchNumber.Focus();
Dynamics.Forms.SopEntry.SopEntry.BatchNumber.Value = "Test";
Dynamics.Forms.SopEntry.SopEntry.BatchNumber.RunValidate();

Visual Studio Tools (VB.Net)

Dynamics.Forms.SopEntry.SopEntry.BatchNumber.Focus();
Dynamics.Forms.SopEntry.SopEntry.BatchNumber.Value = "Test"
Dynamics.Forms.SopEntry.SopEntry.BatchNumber.RunValidate()

Additional methods using Dexterity

There are some additional methods available if using Dexterity which are not exposed to VBA or Visual Studio. When Service Based Architecture (SBA) was added to GP 2015 (v14.0) one of the methods of creating a Service Procedure was to drive the user interface. To simplify this process and get around the old() and diff() issues, a new undocumented map command was added to Dexterity.

To use the map command you must have the data contained in a variable as the command will not evaluate an expression. The map command replicates tabbing into the field and changing the value, the change script does not execute until you either map to another field or take the focus away from the field by either setting it to another field using Window_SetFocus(), or more commonly used, just pull the focus off the window with Window_PullFocus().

local string l_value;
l_value = "Test";

map l_value to 'Batch Number' of window SOP_Entry of form SOP_Entry;
Window_PullFocus(window SOP_Entry of form SOP_Entry);

There is another method which can leverage the open form return to command in Dexterity which is usually used to return data from lookups. This also replicates the user’s behaviour of tabbing to the field, changing the value and tabbing off. However, it requires Dexterity coding and a hidden Dexterity form to work.

Note: There is a MBS_Return Helper Function in GP Power Tools which uses this method and has a number of options about how focus should be controlled and if the the return action should be run “delayed”. GP Power Tools is primarily coded using Dexterity but can run code or call scripts written in C#, VB.Net and SQL.

Hope you find this information and the comparison of languages helpful.

David

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

2 thoughts on “#MSDynGP Development: Driving the User Interface of Microsoft Dynamics GP using Code

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.