The footprint we make on existing objects is a key consideration when it comes to solution maintainability and the associated costs.
Microsoft has made key investments in the development environment in order to make it easier to write code in such a way that it sits alongside another party's solution. The advantage for Microsoft is that their customers can adopt multiple solutions or add-ons from ISVs with minimum effort.
Prior to AX 2012, this effort would have involved merging code from different partners and additional effort would have been required to ensure that a hotfix from one organization did not regress code in another add-on.
The next sections will highlight the practices and technologies that accomplish this.
We are often asked to make changes to AX that require standard objects to be modified; often, the difficult decision is about where the change is to be made.
Firstly, we should consider how the code is structured by taking the example of a form that acts upon a table. Tables are structured into fields, field groups, indexes, relations, delete actions (for example, cascading the deletion to child tables), and methods. Forms are structured into form-level methods, data sources (a reference to a table), and controls. A request might be, "Can we make the vehicle field on the transport form mandatory?"
This is possible; the form control does have this property, as do the data source field and the equivalent field on the table—so, which of these to use? The answer is always as high in the stack as possible. The requirement is that the table always has this particular field filled in, so wherever this field is added, it should be mandatory.
The same pattern applies to code changes—always at the highest level and in this order: class, table, form data source field/method, form control.
Even hiding controls on forms should be handled in a method (which is usually called enableControls
), as this makes the change more obvious and much easier to read, extend, and reuse.
We may already use field groups, and it is best practice to do so. It may seem strange at first that we are creating what are essentially UI components in the data layer, but this pays off in terms of consistent UI and reduced footprint on standard AX. Forms dynamically display the fields that are in that field group; by adding a new field to the appropriate field group, the forms magically display this new field.
The reason this reduces footprint is because we are making one change that affects all forms that refer to the field group, and doesn't affect the form when applying updates.
Eventing is a new key feature in AX 2012 that, along with models, is a key enabler for ISVs to write add-ons for AX.
This technology allows you to subscribe to an event in AX. So, instead of modifying the method, we simply subscribe to it as a pre- or post-event. We can then perform our logic elsewhere in an X++ or a .NET assembly, and even modify method parameters and return values.
This subscription is not a modification to the source method. Therefore, a method can have subscriptions in several different models in the same layer.
Delegates are empty method stubs to which we subscribe. They are created by the original author and called from within their code. This is done so that you can subscribe to events that happen within a method without modifying a method.
For example, the following lines of code would be a delegate written by an ISV (Axp
is the prefix used by this ISV):
delegate void weightCaptured(AxpWeighTicketContract _contract) { }
The ISV will then call this delegate at the appropriate time with the data contract. By subscribing to this delegate, you can handle the event and perform the necessary tasks with the supplier contract. This provides a hook into the supplied solution without modifying it. For more information about the guidelines on delegates, visit http://msdn.microsoft.com/en-us/library/gg879953.aspx.
Another method of modifying behavior with a minimal footprint is to extend the class. This should be done only if you cannot perform the task through an event subscription.
The pattern is implemented with the following steps:
extends
keyword to extend the class you need to change.The table has several events that happen based on form events. In this example for the modified event, the mechanism is conceptualized as follows:
modified
event will call the data source field's modified
methodmodified
event will call the table's modifiedField
event with the field ID of the field being modifiedThe table's modified
event is normally a large switch
statement based on the field ID parameter with a case for each handled field. To modify this, we can simply add a case for our new field or change the behavior of an existing case.
In this situation, we should subscribe to the modifiedField
method, but another option would be to create a new method with the same profile. This is preferable if we are the end-user organization, but is essential for VARs and ISVs. This is done by copying the method header. Let's take a look at the following example:
public void modifiedField(FieldId _fieldId)
We can then create a new method, as follows:
public void conModifiedField(FieldId _fieldId)
Downloading the example code
You can download the example code files from your account at http://www.packtpub.com for all the Packt Publishing books you have purchased. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.
We can then create a switch
statement to handle the fields we need to in this new method. In order to call this new method, we can then add a call to our new method in the original modifiedField
method:
public void modifiedField(FieldId _fieldId) { super(_fieldId); switch (_fieldId) { case fieldNum(<TableName>, <FieldName>): // code break; } // Con Var modification by SB 2014/06/09 handle custom fields this.conModifiedField(_fieldId); }
18.118.140.204