#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)

[code language=”vb”]SalesTransactionEntry.ExpansionButton3 = 1

[/code]

Dexterity (sanScript)

[code]run script ‘Expansion Button 3’ of window SOP_Entry of form SOP_Entry;

[/code]

Visual Studio Tools (C#)

[code language=”csharp”]Dynamics.Forms.SopEntry.SopEntry.ExpansionButton3.RunValidate();

[/code]

Visual Studio Tools (VB.Net)

[code language=”vb”]Dynamics.Forms.SopEntry.SopEntry.ExpansionButton3.RunValidate()

[/code]

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)

[code language=”vb”]SalesTransactionEntry.BatchID = "TEST"

[/code]

Dexterity (sanScript)

[code]’Batch Number’ of window SOP_Entry of form SOP_Entry = "Test";
run script ‘Batch Number’ of window SOP_Entry of form SOP_Entry;

[/code]

Visual Studio Tools (C#)

[code language=”csharp”]Dynamics.Forms.SopEntry.SopEntry.BatchNumber.Value = "Test";
Dynamics.Forms.SopEntry.SopEntry.BatchNumber.RunValidate();
[/code]

Visual Studio Tools (VB.Net)

[code language=”vb”]Dynamics.Forms.SopEntry.SopEntry.BatchNumber.Value = "Test"
Dynamics.Forms.SopEntry.SopEntry.BatchNumber.RunValidate()

[/code]

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)

[code language=”vb”]’ Not possible in VBA because you cannot change a
‘ field value without running the change script

[/code]

Dexterity (sanScript)

[code]’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;
[/code]

Visual Studio Tools (C#)

[code language=”csharp”]Dynamics.Forms.SopEntry.SopEntry.BatchNumber.Value = "Test";
Dynamics.Forms.SopEntry.SopEntry.BatchNumber.ForceValidate(true);
Dynamics.Forms.SopEntry.SopEntry.BatchNumber.Focus();

[/code]

Visual Studio Tools (VB.Net)

[code language=”vb”]Dynamics.Forms.SopEntry.SopEntry.BatchNumber.Value = "Test"
Dynamics.Forms.SopEntry.SopEntry.BatchNumber.ForceValidate(True)
Dynamics.Forms.SopEntry.SopEntry.BatchNumber.Focus()
[/code]

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)

[code language=”vb”]SalesTransactionEntry.BatchID.Focus("TEST")

[/code]

Dexterity (sanScript)

[code]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;

[/code]

Visual Studio Tools (C#)

[code language=”csharp”]Dynamics.Forms.SopEntry.SopEntry.BatchNumber.Focus();
Dynamics.Forms.SopEntry.SopEntry.BatchNumber.Value = "Test";
Dynamics.Forms.SopEntry.SopEntry.BatchNumber.RunValidate();
[/code]

Visual Studio Tools (VB.Net)

[code language=”vb”]Dynamics.Forms.SopEntry.SopEntry.BatchNumber.Focus();
Dynamics.Forms.SopEntry.SopEntry.BatchNumber.Value = "Test"
Dynamics.Forms.SopEntry.SopEntry.BatchNumber.RunValidate()

[/code]

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().

[code]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);

[/code]

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.

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

  1. Michael Nola's avatar

    Hi David,
    running into a problem converting an older VBA modification to VB.NET. The VBA application is able to read the PHONE3 field during the LineFill Event and use it to populate a Modified Form Text Field introduced to the Sales Transaction Entry Line Scroll window. However, the PHONE3 field is not accessible in either of the LineScroll.LineFillBeforeOriginal or LineScroll.LineFillAfterOriginal Events. Also tried reading the Line Item Sequence Number which we could use to know which Line record is currently getting filled in and use that to query the desired value. However, in both instances a BLANK value is returned. We CAN see these values inside the LineScroll.LineEnterBeforeOriginal Event.

    Is there any way in VB.NET to know which SOP Line is being filled (e.g. some way of reading the Line Item Sequence Number during the LineFill event)?

    Had considered coding the change in Dexterity, but correct me if I’m wrong, recall reading another older blog post where you noted that you can’t access Modified Form fields using Dexterity.

    • WinthropDC's avatar

      Hi Michael. Blog comments are not the best way to get technical support. You are correct that Dexterity cannot see Modified fields, however GP Power Tools can. GPPT is the best tool for replacing VBA. It will be able to achieve what you want to do.

      • Michael Joseph Nola's avatar

        Hi David,

        Sorry, meant to send you a THANK YOU response last month and finally found a minute between minutes to properly do so (Thank you!).

        FYI: Was actually able to resolve my issue thanks to an old Patrick Roth repost of yours (Display Specific Line in Sales Order Processing | David Musgrave’s Winthrop Development Consultants Blog (wordpress.com) ). In the post, there was a reference to the underlying SOP Entry table (Microsoft.Dexterity.Applications.Dynamics.Forms.SopEntry.Tables.SopLineWork)which allowed use to reference the SOP Line Work’s PHONE3 field in VB.NET during the LineScrollFill Event.

        Again, thank you very much in helping to resolving this matter.

        Best Regards,

        Michael J. Nola

        mnola@softwaresources.com mnola@softwaresources.com

      • WinthropDC's avatar

        Thanks for the feedback. Did you know that the Developer Tools module of GP Power Tools can do things that Dexterity cannot do, VBA cannot do and VSTools cannot do. It is a much more efficient, maintainable and deployable solution than VSTools. David

Leave a Reply