In Microsoft Dynamics Ax 32-bit you can use any of the following versions:
/COM indicates the 32-bit edition of the ActiveX version
The application built using /COM version runs on any Windows 32 or 64-bit machine.
In Microsoft Dynamics Ax 64-bit you can use any of the following versions:
/COM/64 indicates the 64-bit edition of the ActiveX version
The application built using /COM/64 version runs on Windows 64-bit machine only. The application built using /COM/64 version cannot run on Windows 32-bit machine.
If you want to use your application on 32 and 64-bit machines, you can go for:
/COM/ANY indicates the 32 and 64-bit editions of the ActiveX versions
The Microsoft Dynamics Ax supports ActiveX controls, so you need to install
the /COM version of the component. Go to download
page and click the component you need install in the ActiveX/COM column ( 32
bit ). Click the link, download the component, and the Run it. The installation setup
will install samples, documentation and the /COM version of the component,
that can be used in any Ax forms.
Click the Application Object Tree (AOT), so the AOT window is opened. Open
the Forms folder, and then create a new form, or select an existing one.
Expands the form being selected, so you can see the Designs item, and locate
the Design node. Right-click the Design node for the form, and then select New
Control. Select ActiveX from the submenu. Choose the control that you
want to insert, let's say, ExG2antt Chart ActiveX Control. Click the
Properties of the newly ActiveX member inserted, and go to the Name and type
exg2antt1, so you assign a name for your component.
Generally, the eXHelper
tool generates the form's init method. In other words, you need to override
the init method of your form ( where the control is being inserted or hosted
). In the AOT window, select the Form that hosts the control, expand the
node, so you can see the Methods node. Right Click the Methods node, and
select the Override Method from submenu, and init from the next submenu. So,
your Ax environment will generate the following code:
public void init()
{
super();
}
Now, open the exhelper tool. Select the component you want to copy code
from in the left side drop down. Click the Help button, so the questions are
loaded, and the control is read to be used in the exhelper. Select the
question you want to copy the code, and then double click it, or press ENTER
key. The component panel will show the control in running state, and the
middle panel shows the x-script language you want to convert. Click the ...
button on the horizontal scroll bar (middle panel), and select the X++
(Dynamics Ax 2009), so the middle panel will show the X++ code you can copy
and paste directly on your form's init method.
In the AOT window, select the Form that hosts our component. Expand it, so
you can locate the Designs\Design\ActiveX:. Right click the ActiveX node (
under the Design node ), and select the ActiveX Explorer from the
submenu, so the list of events and methods for the component is displayed.
In the Event tab page locate the event you need to handle, and click the
Add, and then Edit, so the Ax environment adds the empty handler for you.
For instance, let's say you need to handle the BeforeExpandItem
event of the eXG2antt component, so you need to locate the void
onEvent_BeforeExpandItem(int _Item, COMVariant /* variant */ _Cancel).
// Fired before an item is about to be expanded (collapsed).
void onEvent_BeforeExpandItem(int _Item, COMVariant /* variant */ _Cancel)
{
}
Another way is using the the Event
which notifies your application once a new event is fired by the control.
The EventParam
property gets the value of specified parameter during an event, and it is
valid ONLY during the control's event. The definition for all events can be
found on the control's documentation.
The following sample displays information about the firing event:
// Event event - Notifies the application once the control fires an event.
void onEvent_Event(int _EventID)
{
;
print(exg2antt1.EventParam(-2));
}
The EventParam property can be used as follows:
The EventParam(-2) to gets the entire information about fired event (
such as name, identifier, and parameters ) as a string.
The EventParam(-1) retrieves the number of available parameters for
current event.
The EventParam(Index) retrieves the parameter with specified Index,
where index should be greater or equal with Zero and less than number of
parameters for the current event
During the Event handler you can use the EventParam to access the
parameters of the current event.
For instance the following X++ sample displays the name of the bar being
resized, in the eXG2antt control:
// Event event - Notifies the application once the control fires an event.
void onEvent_Event(int _EventID)
{
;
// event BarResize (Item as HITEM, Key as Variant)
if (_EventID == 120)
{
print(exg2antt1.ExecuteTemplate("Items.ItemBar(Me.EventParam(0),Me.EventParam(1),0)"));
}
}
where the 120 is the identifier of the BarResize
event ( which can be determined using the EventParam(-2) ), the ExecuteTemplate
property provides the result of executing the x-script template at runtime.
The Items.ItemBar(Item,Key,Property)
returns the value for a specified property of a specified bar being
indicated by Item and key. The Item parameter of the BarResize is getting by
the EventParam(0), the Key using the EventParam(1), and 0 indicates the
identifier for the exBarName property. In conclusion, the sample displays
the name of the bar being resize or moved using the x-script and
ExecuteTemplate method.
Generally, the parameters passed by reference are of COMVariant type. Our component provide the
EventParam
method that can be used to access or change the parameters of the event, as
described in the following samples. For
instance, let's say you need to handle the BeforeExpandItem
event of the eXG2antt component, which has the Cancel parameter which
indicates whether the control should expand / collapse an item. Setting this
parameter on False, will prevent the control to expand or collapse the item.
So, generally you will write the code:
// Fired before an item is about to be expanded (collapsed).
void onEvent_BeforeExpandItem(int _Item, COMVariant /* variant */ _Cancel)
{
;
_Cancel = True;
}
but it will gives the compiler error: *** Error: 1, Operand types are not compatible with the
operator. So, the next step is to correct the error. Since the _Cancel
parameter is of COMVariant type as seen in the event's declaration, we need
to make sure that the value being passed to _Cancel parameter will be a
COMVariant type, not a boolean directly, so we need to lool for static
members of the COMVaraint type ( just type COMVariant::, and the environment
will show you the list of static members you can use ). In our case we
should look for COMVariant::createFromBoolean which will do the trick, so
the code will shows as:
// Fired before an item is about to be expanded (collapsed).
void onEvent_BeforeExpandItem(int _Item, COMVariant /* variant */ _Cancel)
{
;
_Cancel = COMVariant::createFromBoolean(True);
}
Now, the code is compiled just fine, but still if we run the sample, the
user is still able to expand or collapse an item. Now, we reach the
conclusion, that actually the Dynamics Ax can not handle, or pass back to
the client, the changed value. Our component provide the EventParam
method that can be used to access or change the parameters of the event. So
the code will show as:
// Fired before an item is about to be expanded (collapsed).
void onEvent_BeforeExpandItem(int _Item, COMVariant /* variant */ _Cancel)
{
;
exg2antt1.EventParam( 1, COMVariant::createFromBoolean(True) );
}
The first parameter of the EventParam method indicates the index (0
based) of the parameter being accessed. In this case, the event has two
parameters, the first _Item with the index 0, and the _Cancel with the index
1.
The following X++ samples displays the start point of the bar being
resized, in the eXG2antt control:
// Notifies the application once the control fires an event.
void onEvent_Event(int _EventID)
{
COM com_Items;
anytype var_Items;
COMVariant vStart;
date dtStart;
;
// event BarResize (Item as HITEM, Key as Variant)
if (_EventID == 120)
{
var_Items = exg2antt1.Items(); com_Items = var_Items;
vStart = com_Items.ItemBar(exg2antt1.EventParam(0),exg2antt1.EventParam(1),1);
dtStart = vStart.date();
print(dtStart);
}
}
The following X++ samples displays the start point of the bar being
resized, in the eXG2antt control ( similar with the previously sample,
excepts that it uses the ExecuteTemplate
property):
// Notifies the application once the control fires an event.
void onEvent_Event(int _EventID)
{
str sResult;
COMVariant vStart;
date dtStart;
;
// event BarResize (Item as HITEM, Key as Variant)
if (_EventID == 120)
{
vStart = exg2antt1.ExecuteTemplate("Items.ItemBar(Me.EventParam(0),Me.EventParam(1),1)");
dtStart = vStart.date();
print(dtStart);
}
}
The control provides Template
and ExecuteTemplate
properties that can be used to execute x-script templates. Shortly, an
x-script is a string that control can execute. The Template method does not
return any result, while the ExecuteTemplate property returns the last
result from the x-script. Both commands are cumulative, in other words. For
instance calling the Template("Columns.Add(0)") multiple times,
adds a new column for each call. So, calling the Template/ExecuteTemplate
property does not reset the control.
For instance, the following sample changes the control's background color
using x-script and Template property:
public void init()
{
;
super();
exg2antt1.Template("BackColor = RGB(255,0,0)");
}
The following sample displays the BackColor's property value using the
ExecuteTemplate property
In conclusion, the Template property can execute any x-script code
without returning any result, while the ExecuteTemplate property executes
and returns the last result of the code.
For instance the following X++ sample displays the name of the bar being
resized, in the eXG2antt control:
// Notifies the application once the control fires an event.
void onEvent_Event(int _EventID)
{
COMVariant vResult;
;
// event BarResize (Item as HITEM, Key as Variant)
if (_EventID == 120)
{
vResult = exg2antt1.ExecuteTemplate("Items.ItemBar(Me.EventParam(0),Me.EventParam(1),0)");
print(vResult.toString());
}
}
where the 120 is the identifier of the BarResize event ( which can be
determined using the EventParam(-2) ), the ExecuteTemplate property provides
the result of executing the x-script template at runtime. The Items.ItemBar(Item,Key,Property)
returns the value for a specified property of a specified bar being
indicated by Item and key. The Item parameter of the BarResize is getting by
the EventParam(0), the Key using the EventParam(1), and 0 indicates the
identifier for the exBarName property. In conclusion, the sample displays
the name of the bar being resize or moved using the x-script and ExecuteTemplate
method.
For instance the following X++ sample displays the start point of the bar being
resized, in the eXG2antt control:
// Notifies the application once the control fires an event.
void onEvent_Event(int _EventID)
{
str sResult;
COMVariant vStart;
date dtStart;
;
// event BarResize (Item as HITEM, Key as Variant)
if (_EventID == 120)
{
vStart = exg2antt1.ExecuteTemplate("Items.ItemBar(Me.EventParam(0),Me.EventParam(1),1)");
dtStart = vStart.date();
print(dtStart);
}
}
where the 120 is the identifier of the BarResize event ( which can be
determined using the EventParam(-2) ), the ExecuteTemplate property provides
the result of executing the x-script template at runtime. The Items.ItemBar(Item,Key,Property)
returns the value for a specified property of a specified bar being
indicated by Item and key. The Item parameter of the BarResize is getting by
the EventParam(0), the Key using the EventParam(1), and 0 indicates the
identifier for the exBarStart property. In conclusion, the sample displays
the starting point of the bar being resize or moved using the x-script and ExecuteTemplate
method.
This may occurs when handling events that have parameters passed by
reference. Passed by reference, means that in the event handler, you can
change the value for that parameter, and so the control will takes the new
value, and use it. The X++ is NOT able to handle properly events with
parameters by reference, so we have the solution.
The solution is using and handling the Event notification and EventParam
method., instead handling the event that gives the "invalid parameters"
error executing code.
Let's presume that we need to handle the BarParentChange event to change
the _Cancel parameter from false to true, which fires the "Error executing code: FormActiveXControl (data source), method onEvent_BarParentChange called with invalid parameters."
We need to know the identifier of the BarParentChange event ( each event has
an unique identifier and it is static, defined in the control's type library
). If you are not familiar with what a type library means just handle the
Event of the control as follows:
// Notifies the application once the control fires an event.
void onEvent_Event(int _EventID)
{
print exg2antt1.EventParam(-2).toString();
}
This code allows you to display the information for each event of the
control being fired as in the list bellow:
Each line indicates an event, and the following information is
provided: the name of the event, its identifier, and the list of
parameters being passed to the event. The parameters that starts with =
character, indicates a parameter by reference, in other words one that can
changed during the event handler.
Now, we can see that the identifier for the BarParentChange event is 125,
so we need to handle the Event event as:
// Notifies the application once the control fires an event.
void onEvent_Event(int _EventID)
{
;
if ( _EventID == 125 ) /*event BarParentChange (Item as HITEM, Key as Variant, NewItem as HITEM, Cancel as Boolean) */
exg2antt1.EventParam( 3 /*Cancel*/, COMVariant::createFromBoolean(true) );
}
The code checks if the BarParentChange ( _EventID == 125) event is fired,
and changes the third parameter of the event to true. The definition for
BarParentChange event can be consulted in the control's documentation or in
the ActiveX explorer. So, anytime you need to access the original parameters
for the event you should use the EventParam method that allows you to get or
set a parameter. If the parameter is not passed by reference, you can not
change the parameter's value.
Now, let's add some code to see a complex sample, so let's say that we
need to prevent moving the bar from an item to any disabled item. So, we
need to specify the Cancel parameter as not Items.EnableItem(NewItem), in
other words cancels if the new parent is disabled. Shortly the code will be:
// Notifies the application once the control fires an event.
void onEvent_Event(int _EventID)
{
;
if ( _EventID == 125 ) /*event BarParentChange (Item as HITEM, Key as Variant, NewItem as HITEM, Cancel as Boolean) */
if ( !exg2antt1.Items().EnableItem( exg2antt1.EventParam( 2 /*NewItem*/ ) ) )
exg2antt1.EventParam( 3 /*Cancel*/, COMVariant::createFromBoolean(true) );
}
In conclusion, anytime the X++ fires the "invalid parameters."
while handling an event, you can use and handle the Event notification and
EventParam methods of the control.
The Exontrol ExPrint
component is an advanced printing system specifically to bring your User
Interface to the printed page. The eXPrint component provides print and
print preview capabilities for our UI components. First, we
need to insert the exprint component to the form or dialog. Click the
Application Object Tree (AOT), so the AOT window is opened. Open the Forms
folder, and then create a new form, or select an existing one. Expands the
form being selected, so you can see the Designs item, and locate the Design
node. Right-click the Design node for the form, and then select New Control.
Select ActiveX from the submenu. Choose the control that you want to insert,
in our case, ExPrint ActiveX Control. Click the Properties of the newly
ActiveX member inserted, and go to the Name and type exprint1, so you assign
a name for your component. Specify the Visible property of the exprint1 on
False, so it won't be visible at runtime ( it is a windowless control ).
Now, once the exprint1 component is added to the same form where the
control to be printed is hosted ( exprint1.Visible property is false, so the
exprint component will not be visible at runtime ), we can use the following
function to preview the control:
In this sample, the exg2antt1 indicates the component to be printed, so
you need to change with the name of the component you would like to
preview.
If the wrong object is being used in the PrintExt method, the environment
will display a message in your Infolog such as: "Method 'Preview' in COM object of class
'IExPrint' returned error code 0x80020009 (DISP_E_EXCEPTION) which means: The PrintExt property must be set before calling Preview method."
This indicates that you are trying to preview a non-exontrol component, or
an exontrol component with no print and print-preview support.
Generally, the eXPrint component provides support for the following
components:
This issue is related to eXG2antt or eXGantt components. Generally, it is
caused by the Chart.PaneWidth
property during the init method of the form. At the time, the init method is
performed, the control's size is 0 ( so it's width is 0 ), so setting the
PaneWidth during the init, will not have any effect, as the specified width
should be between 0 and the control's width ( which is 0 at the init method
). In order to fix this, you can handle the activate method of the form and
call the PaneWidth during the activate event as follows:
public void activate(boolean _active)
{
super(_active);
exg2antt1.Chart().PaneWidth(false,128);
}
You can call the PaneWidth during any form's event, and it has effect
only if at the moment of setting, the control's width is not 0.
This compiler error 74 may occur if calling a sequence of methods that includes
parameters in a single line. This could be a limitation of the X++
complier.
This error can be avoided, if the X++ line is divided in more instructions
as in the following samples. Shortly, whenever you use a property that
returns an object, just declare a variable of type COM and use the variable
next time, as you can see in the following samples:
Here's a situation where the red line indicates the "*** Error 74, The variable is not of the type CLASS."
compiler error.
public void init()
{
;
super();
exg2antt1.Chart().Bars().Item("Task").Color(255);
}
Generally, if a line contains calling several methods with parameters you
need to divide it, as follows:
public void init()
{
COM com_Bars,com_Bar,com_Chart;
;
super();
com_Chart = exg2antt1.Chart();
com_Bars = com_Chart.Bars();
com_Bar = com_Bars.Item("Task");
com_Bar.Color(255);
}
In most cases you still can use the COM::createFromObject method as in
the following samples:
public void init()
{
COM com_bars;
;
super();
com_bars = COM::createFromObject(exg2antt1.Chart().Bars());
COM::createFromObject(com_bars.Item("Task")).Color(255);
}
Another situation, where the red line indicates the "*** Error 74, The variable is not of the type CLASS."
compiler error., is:
public void init()
{
;
super();
exg2antt1.Columns().Add("Task").HeaderBold(True);
}
In order to correct the error, we need to look for the first method that
include parameters, so it would be Add. If we check the control's help the Add
method of the Columns object returns a Variant, but still contains an object
( a Column object ), so all we need is to convert the return of Add to a COM
type as in the following sample:
public void init()
{
;
super();
COM::createFromVariant(exg2antt1.Columns().Add("Task")).HeaderBold(True);
}