Dynamics GP Developer Insights: Web Client Window Ribbon - Part 2

Rushi Patel - Click for blog homepageHey, I am Rushi Patel. I am a software developer working on the Microsoft Dynamics GP team in Fargo the last 3 years. I like to spend my time with my family, watching movies and cricket.

At Microsoft, I have worked on Office Accounting and Dynamics GP Workflow prior to my current project – the GP web client. I mostly worked on the UI features of web client before I started working on the Window Ribbon feature. Window Ribbons, as the name implies, appears to be a purely UI concept. That’s true, however there are many dependencies to make Window Ribbons render on web client such as sanScript code and Dexterity support/enhancements that will be explained in depth in this series of articles.

Note: Click on the images for larger versions.


This post is continued from last week's post.

Customized Ribbon

As you can imagine, the Default Ribbon Rules might not cater to needs of all the windows on the web client. There are situations where there needs to be a customized Window Ribbon for a certain functionality.  This can be done by overriding the default rules and setting the Window Ribbon up as needed for those windows. I’ll discuss this after I explain the design for the window ribbons.

Design & Implementation Details

We leveraged the design of the existing Dynamics GP desktop client list page Ribbon that uses Command(s) and Command List(s) for Dynamics GP Window Ribbons.

To support everything on the Dynamics GP Web Client some new properties were needed such as Button Size, to support the Window Ribbon rendering and these have been made available to support the desktop client Ribbons.

InitializeDefaultRibbon_Main or InitializeDefaultRibbon Global Script

IntializeDefaultRibbon_Main procedure is in the core dictionary. This procedure will create the default ribbon command list structure which will be sufficient for most windows. Any necessary window level customizations to the Window Ribbon need to be done in that windows form InitializeWindowRibbon procedure.

If the default Window Ribbon rules need to be overridden a 3rd party dictionary can create an InitializeDefaultRibbon global procedure which, if it exists, will be called by the Dexterity Runtime instead of InitializeDefaultRibbon_Main procedure of the core dictionary. If the procedure does not exist, InitializeDefaultRibbon_Main will be called for that 3rd party dictionary and receive all the default rules defined by the core product.

InitializeWindowRibbon Form Level Procedure

This is an optional form level procedure that will allow for any necessary customizations to be made to the Window Ribbon command list. If this is necessary, it should always follow a call to the InitializeDefaultRibbon global script to take advantage of the default logic to build the Window Ribbon.

Dexterity Runtime Logic

New Dexterity API(s)

Lots of thought and design went into making sure we could implement the Window Ribbon functionality and allow for customizations. As such there has been new functionality added to the Dexterity tool to accommodate these. Some of those new functions and APIs leveraged for Window Ribbons are the following:

  1. CommandList_CreateList
    This API creates a command list that is associated with the specified form.  The list is created empty and must be manipulated using the already-existing command based functions.  The list will be unloaded when the form closes.
     
  2. Window_GetRibbonCommandTag
    This API gets the command tag of the command list that serves as the "ribbon root" for the specified window. 
     
  3. Form_GetMenuListCommandTag
    This API gets the command that is associated with the static form-level menu list of the specified form.  The list returned is not the 'Extras' menu whose contents vary based on the current focus, but rather points to a list whose contents are fixed at the time the form loads.
     
  4. Field_CreateLinkedCommand
    This API creates a command that is associated with the specified field.  The command will be associated with the same form as the field and will be unloaded at the same time the form is cleaned up.
      
    Since for Dynamics GP web client we are moving fields to the Window Ribbon commands, any changes to the field (such as hiding and disabling) need to be done for command as well. Manually doing those changes in app code is a challenge. This API will help us link command to the field that will take necessary actions on the command when the field property changes.
     
  5. Field_GetLinkedCommandTag
    This API gets the command that is linked to the specified field.
     
  6. Field_BDLCreateLinkedCommandList
    This API creates a command list that is associated with the specified button drop list.  The list is structured just like the BDL (in terms of the hierarchy).  Also, it will be associated with the same form as the BDL and will be unloaded at the same time the form is cleaned up.
     
    As mentioned in point 4, this API will help us link BDL field to the command to take advantage of auto actions performed on the command when field property changes. Any add, remove or update operations performed on a BDL item will be applied to the linked command as well.
     
  7. Field_BDLGetLinkedItemCommandTag
    This API gets the command associated with a button drop list item that is part of the control's linked command list.

How to customize a Window Ribbon?

Example 1:

The default Ribbon rules doesn’t include any Edit menu related commands. But we want to have Insert Row and Delete Row buttons from Edit Menu as Window Ribbon items under Actions group on the web client.

InitializeWindowRibbon procedure

{InitializeWindowRibbon procedure}

in integer productId;
in integer formId;
in integer windowId;
in integer windowType;
inout integer ribbonTag;

local string windowName;

{call InitializeDefaultRibbon}

windowName = Resource_GetSubResourceName(productId, MT_FORM, formId, DT_WINDOW, windowId);

if (windowName = “POP_Invoice_Entry”) then

{Add insert row to actions group}
cmdTag = Command_GetTag(command 'cmdInsertRow');
Command_SetStringProperty(cmdTag, COMMAND_PROP_DISPLAY_NAME, “Insert Row”); CommandList_Add(actionGroup, cmdTag);

{Add delete row to actions group}
cmdTag = Command_GetTag(command 'cmdDeleteRow');
Command_SetStringProperty(cmdTag, COMMAND_PROP_DISPLAY_NAME, “Delete Row”); CommandList_Add(actionGroup, cmdTag);

end if;

  

Example 2:

We want to move buttons to the Window Ribbon in web client. As shown below we are moving Bins, Quantity Type, Distributions and Serial/Lot buttons to the Go To group on the Window Ribbon in the web client.

InitializeWindowRibbon procedure

{InitializeWindowRibbon procedure}

in integer productId;
in integer formId;
in integer windowId;
in integer windowType;
inout integer ribbonTag;

local string windowName;
local integer fileGroup, helpGroup, actionGroup, gotoGroup, additionalGroup, viewGroup, optionsGroup, workflowGroup, clFormMenu;

{call InitializeDefaultRibbon}
call InitializeDefaultRibbon of form syWebClientRibbon, productId, formId, windowId, ribbonTag, fileGroup, helpGroup, actionGroup, gotoGroup, additionalGroup, viewGroup, optionsGroup, workflowGroup, clFormMenu;

windowName = Resource_GetSubResourceName(productId, MT_FORM, formId, DT_WINDOW, windowId);

if(windowName = “IV_Transaction_Inquiry”) then

{Seup Goto group}
clGoTo = CommandList_CreateList(productId, formId, CL_GOTO);
Command_SetStringProperty(cmdTag, COMMAND_PROP_DISPLAY_NAME,”GoTo”);  

 {Add Bins Button}
cmdTag = Field_CreateLinkedCommand('(L) Bins Button' of window IV_Transaction_Inquiry, "(L) Bins Button_w_IV_Transaction_Inquiry_f_IV_Transaction_Inquiry");
Command_SetStringProperty(cmdTag, COMMAND_PROP_DISPLAY_NAME, Field_GetStringProperty('(L) Bins Button' of window IV_Transaction_Inquiry, FIELD_PROP_CAPTION));
CommandList_Add(clGoTo, cmdTag);

{Add Distributions Button}
cmdTag = Field_CreateLinkedCommand('Distributions Button' of window IV_Transaction_Inquiry, "Distributions Button_w_IV_Transaction_Inquiry_f_IV_Transaction_Inquiry");
Command_SetStringProperty(cmdTag, COMMAND_PROP_DISPLAY_NAME, Field_GetStringProperty('Distributions Button' of window IV_Transaction_Inquiry, FIELD_PROP_CAPTION));
CommandList_Add(clGoTo, cmdTag);

{Add Serial/Lot Button}
cmdTag = Field_CreateLinkedCommand('Serial/Lot Button (/)' of window IV_Transaction_Inquiry, "Serial/Lot Button (/)_w_IV_Transaction_Inquiry_f_IV_Transaction_Inquiry");
Command_SetStringProperty(cmdTag, COMMAND_PROP_DISPLAY_NAME, Field_GetStringProperty('Serial/Lot Button (/)' of window IV_Transaction_Inquiry, FIELD_PROP_CAPTION));
CommandList_Add(clGoTo, cmdTag);

{Add Quantity Type Button}
cmdTag = Field_CreateLinkedCommand('Quantity Type Button Q' of window IV_Transaction_Inquiry, "Quantity Type Button Q_w_IV_Transaction_Inquiry_f_IV_Transaction_Inquiry");
Command_SetStringProperty(cmdTag, COMMAND_PROP_DISPLAY_NAME, Field_GetStringProperty('Quantity Type Button Q' of window IV_Transaction_Inquiry, FIELD_PROP_CAPTION));
CommandList_Add(clGoTo, cmdTag);

CommandList_Add(gotoGroup, clGoTo);
end if;

 

 

Example 3:

This example shows how to suppress the Window Ribbon for a specific window in the form. Suppose Form1 contains Window1 and Window2. We want a Ribbon on Window1 and not on Window2.

InitializeWindowRibbon procedure

{InitializeWindowRibbon procedure}

in integer productId;
in integer formId;
in integer windowId;
in integer windowType;
inout integer ribbonTag;

local string windowName;

windowName = Resource_GetSubResourceName(productId, MT_FORM, formId, DT_WINDOW, windowId);

if(windowName = “Window1”) then
{Suppress Ribbon}
ribbonTag = 0;
else
{call InitializeDefaultRibbon}
end if;

  

Summary

So today, we learned about the Window Ribbon support in Dynamics GP web client. It gives details about the default Window Ribbon rules, why do we need those rules and the Window Ribbon design. Most importantly it gives you details about how to customize the Window Ribbon and its default rules. In close, we hope that you have found this article useful and informative.

Rushi Patel

For other posts in this series go to: https://blogs.msdn.com/b/developingfordynamicsgp/archive/tags/developer+insights/