Hi,
I found some useful information regarding the updation of the updated current row record from the "Dynamics AX tools and tutorials" blog.
It may be helpful to someone.
In order to update the display options for a specific row that you updated, you can use the clearDisplayOption method on the FormDataSource class.
So, after calling
yourDS_ds.reread();
yourDS_ds.refresh();
you should call
yourDS_ds.clearDisplayOption(yourDS);
This should do the trick and update the color of the row.
Regards,
/Ashlesh
Wednesday, December 29, 2010
Friday, November 19, 2010
Add Label Files to Repository
Hi,
To use Labels (*.ald) files in Version Control system in AX 2009. It is required to do below steps:
1. Go to Tools/Development Tools/Version Control/Setup/Add Label File.
2. In the form shown, type some description for VSS history records and browse the *.ald file which contains your labels.
3. Click "OK".
4. Go to Tools/Development Tools/Version Control/Synchronize. and synchronize the Label Files.
Now label files are added to your version control system (Repository) and ready to use through your AOT.
Regards,
/Ashlesh
To use Labels (*.ald) files in Version Control system in AX 2009. It is required to do below steps:
1. Go to Tools/Development Tools/Version Control/Setup/Add Label File.
2. In the form shown, type some description for VSS history records and browse the *.ald file which contains your labels.
3. Click "OK".
4. Go to Tools/Development Tools/Version Control/Synchronize. and synchronize the Label Files.
Now label files are added to your version control system (Repository) and ready to use through your AOT.
Regards,
/Ashlesh
Tuesday, November 9, 2010
Guide for Container in MorphX
Hi,
I found a good article from Axaptapedia related to Container datatype in MorphX.
Containers are a basic form of linked lists. Container functions that you might need are conins, conpoke, conpeek, condel and connull.
A container can store almost any datatype, except of objects. You can store a record/tablebuffer and BinData as a blob inside of a container.
One use of containers is to pass multiple variables between objects using a single call. This is particularly useful when considering 3-tier performance, as each call across a tier can be quite expensive. In that case, putting your variables into one container and passing that in a single call will gain some performance.
Another use is to eliminate some tedious coding practices when writing display methods for report labels. If you have to return values from tables just use a container to store them all then conpeek them out using a global incremental pointer. This pointer can be reset in the executeSection of your Design then use the same method for the DataMethod of your report label something like
To declare a container simply prefix the container name with keyword container.
Inserting data
I found two methods of inserting data into a container, one is using conins(container, start location, value1,...) same syntax can be used for conpoke(container, start location, value1,...). Using conpoke will actually modify data at that location as opposed to inserting, the idea is that initially you can build your container with conpoke but if your container will need data added then use conins which will insert the data at specified location and bump the rest of the data.
Appending data
The normal way to append data to variable is
The best way for appending data to a container is:
Compare
Its also possible to compare 2 containers with each other using the normal operators ==, >, >=, <, <=, !=. Comparing containers results in comparing the content, the first element of container 1 will be compared with the first element of container 2, and so on..... until the comparision gets a result!
Display a container
for displaying the content and structure of a container, use the static-method conview of the class global. conview creates a formRun-Object showing the container as a tree. This formRun can be shown as a normal form or it can be used as lookup-form.
This whole thing is especially tricky in cases where you need variable-length containers which you usually create dynamically: This actually scales rather bad. However, there is a rather simple trick you can use if you run into this problem: The integrated List class does have a very nice packed format, which is just about what you need:
I found a good article from Axaptapedia related to Container datatype in MorphX.
Container
From Axaptapedia
Jump to: navigation, search
[edit] Containers
DescriptionContainers are a basic form of linked lists. Container functions that you might need are conins, conpoke, conpeek, condel and connull.
A container can store almost any datatype, except of objects. You can store a record/tablebuffer and BinData as a blob inside of a container.
One use of containers is to pass multiple variables between objects using a single call. This is particularly useful when considering 3-tier performance, as each call across a tier can be quite expensive. In that case, putting your variables into one container and passing that in a single call will gain some performance.
Another use is to eliminate some tedious coding practices when writing display methods for report labels. If you have to return values from tables just use a container to store them all then conpeek them out using a global incremental pointer. This pointer can be reset in the executeSection of your Design then use the same method for the DataMethod of your report label something like
display real showValue() { pointer++; return any2real(conpeek(yourcontainer,pointer)); }Declaration
To declare a container simply prefix the container name with keyword container.
static void Job33(Args _args) { container contest; ; }
Inserting data
I found two methods of inserting data into a container, one is using conins(container, start location, value1,...) same syntax can be used for conpoke(container, start location, value1,...). Using conpoke will actually modify data at that location as opposed to inserting, the idea is that initially you can build your container with conpoke but if your container will need data added then use conins which will insert the data at specified location and bump the rest of the data.
static void Job33(Args _args) { container contest; ; contest =conpoke(contest,1,"bla",3); //contest = conins(contest,1,"bla",3); print conpeek(contest,2); pause; }In the above I use conpoke to insert two values starting at location 1 into contest. So after this our container will ... contain :) value "bla" at location 1 and value 3 at location 2. Data type for values is anytype. conpeeek returns anytype data type.
Appending data
The normal way to append data to variable is
// e.g. using a string testString = testString + 'append data' // e.g. using a container contest = contest + ['next value'];A problem for this operation with large containers will discussed in the next chapter.
The best way for appending data to a container is:
// use this way to append data contest += ['next value']; // instead of this contest = contest + ['next value']The += is much faster and needs less memory than the normal way...
Compare
Its also possible to compare 2 containers with each other using the normal operators ==, >, >=, <, <=, !=. Comparing containers results in comparing the content, the first element of container 1 will be compared with the first element of container 2, and so on..... until the comparision gets a result!
Display a container
for displaying the content and structure of a container, use the static-method conview of the class global. conview creates a formRun-Object showing the container as a tree. This formRun can be shown as a normal form or it can be used as lookup-form.
static void testContainer(Args _args) { container testContainer1,testContainer2; ; testContainer1 = [ 'Hello World', today(), DocumentStatus::Invoice ]; testContainer2 = [ CustTable::find('4004'), testContainer1, 'blabla' ); conview(testContainer1); global::conview(testContainer2); }
[edit] Performance considerations
One important detail about containers is the fact, that they are static structures. You cannot modify a container in-place, instead each addition or deletion has to iterate over the entire structure to copy all values into a newly allocated one. So every container manipulation has a runtime of O(n). Thus, whenever possible, read and write containers as a batch:// writing a container packedClass = [ version, var1, var2, var3 ]; // reading a container [ version, var1, var2, var3 ] = packedClass;I cannot tell how this is for reading operations, I suspect that they're O(1) much like arrays, but I wouldn't bet anything on it.
This whole thing is especially tricky in cases where you need variable-length containers which you usually create dynamically: This actually scales rather bad. However, there is a rather simple trick you can use if you run into this problem: The integrated List class does have a very nice packed format, which is just about what you need:
static container List2Container(List list) { container result; result = list.pack(); switch (conpeek(result, 1)) { case 1: return condel(result, 1, 3); default: throw error(strfmt("The List version %1 is not suppported.", conpeek(result, 1))); } }I had performance problems in this respect with containers having 50+ elements which have to be assembled dynamically (for various reasons not important here). Changing to a list and converting it into a container in a single batch is at least one magnitude faster there (no wonder, as appending to a list works in O(1) rather then O(n)).
Tuesday, November 2, 2010
To view newly added Item in ItemDetails form Grid
When you created the record in the InventTable form, the following tables were changed: 1. InventTable - added one line - the one you see in the grid 2. InventTableModule - added 3 lines - for Purch, Sales and Invent modules 3. InventItemLocation - added 1 line You have to import into all 3 tables. Then the records in the grid will be visible.
Regards,
/Ashlesh
Monday, October 25, 2010
Using record templates in code for Dynamics Ax 4.0.
This article deals with defaulting values from record templates through code in Dynamics Ax 4.0.
Whenever you creat a new record in the Item form, a small form opens up showing up the templates. You can choose one of the templates from which you want to the basic values like "Item Group", "Dimension Group" to be copied.(Provided you have setup a template for that table).
This comes handy to create new records further as most of the value is drawn from the template record itself. You can harness this when you do it through code also :) .... The following lines will throw light on how to do it.
1. Assume that you have the template name, then all that you need is to create a new record based on the template.
These three lines will do the job...
These three lines will do the job...
sysRecordTemplate = SysRecordTemplate::newCommon(inventTable);
sysRecordTemplate.parmForceCompanyTemplate('WMSY01'); //Template name as string
sysRecordTemplate.createRecord();There are two kind of templates one common for the entire company and the other for specific user. In my example i have taken the company template, for the simple reason that it is valid across all accounts.
2. The above code pressumes that you might know the template name in prior. Sometimes you may want to give user a option of telling what template he wants to use. In that case we may need to create a template for him.
2. The above code pressumes that you might know the template name in prior. Sometimes you may want to give user a option of telling what template he wants to use. In that case we may need to create a template for him.
Here is the code that will enable the lookup and validate the selection. Bind these methods to the control where the user selects.
//Call this method in the init method of formSysRecordTmpTemplate VCTInitItemTemplates() { Container recordValues; ; recordValues = SysRecordTemplateTable::find(tablenum(inventTable)).Data; recordValues = condel(recordValues,1,1); //tmp1 - Global variable for lookup SysRecordTmpTemplate::insertContainer(tablenum(inventTable), tmp1, recordValues, SysRecordTemplateType::Company, true); //tmp2 - Global variable for validation SysRecordTmpTemplate::insertContainer(tablenum(inventTable), tmp2, recordValues, SysRecordTemplateType::Company, true); return tmp; }//Override the lookup methodpublic void lookup() { SysTableLookup sysTableLookup; SysRecordTmpTemplate tmp; Container recordValues; ; super(); sysTableLookup = SysTableLookup::newParameters(tablenum(SysRecordTmpTemplate), this); //Add the fields to be shown in the lookup form sysTableLookup.addLookupfield(fieldnum(SysRecordTmpTemplate, Description), true); sysTableLookup.parmUseLookupValue(false); sysTableLookup.parmTmpBuffer(tmp2); // Perform lookup sysTableLookup.performFormLookup(); }
//Override the modified method
public boolean modified()
{
boolean ret;
SysRecordTmpTemplate tmp;
container recordValues;
;
ret = super();
select firstonly tmp2 where tmp2.Description == this.valueStr();
if (!tmp2 && this.valueStr())
{
this.text('');
warning ('Invalid selection.');
return false;
}
return ret;
}This also helps you learn usage of temporary tables for lookup's. The following line enables lookups through temporary table.
sysTableLookup.parmTmpBuffer(tmp2);
Hope now you can implement a full fledged code that will create it's record from an pre exisiting template.
Regards,
/Ashlesh
Friday, October 1, 2010
Error in pack/unpack method while using LocalMacro.CurrentList and CurrentVersion
Hi,
I faced the problem while using dialog field in my class. I have declared a dialogfield variable for EDT but while assigning the value from the dialog it is not able to keep the assigned value throughout the class where it is being used.
I found some blogs that, by the use of Local Macro (CurrentVersion and CurrentList) you can resolve this issue. But the concept of CurrentVersion is much complicated with it.
Key Point: You have to manually increase the value of CurrentVersion declared as and when you add the dialogfield into the CurrentList macro.
By using above i can able to use the dialog field throughout the class.
Hope this helps to someone.
Regards,
/Ashlesh
I faced the problem while using dialog field in my class. I have declared a dialogfield variable for EDT but while assigning the value from the dialog it is not able to keep the assigned value throughout the class where it is being used.
I found some blogs that, by the use of Local Macro (CurrentVersion and CurrentList) you can resolve this issue. But the concept of CurrentVersion is much complicated with it.
Key Point: You have to manually increase the value of CurrentVersion declared as and when you add the dialogfield into the CurrentList macro.
By using above i can able to use the dialog field throughout the class.
Hope this helps to someone.
Regards,
/Ashlesh
Friday, September 17, 2010
Create New Folder(Directory Path) using Morph X
// Verifyes or creates Path
//
static client public boolean createDirectoryPath()
{
int ptr;
FilePath _path = xinfo::directory(directorytype::Bin) + '\Image';
;
_path = strLRTrim(_path);
if (substr(_path,strlen(_path),1) != '\\') // Adding backslash gives a more simple while-loop!
{
_path += '\\';
}
//MKU: enables creation of UNC paths, by detecting which folder already exists (backwards).
ptr = strLen(_path);
ptr = strfind(_path, '\\', ptr, -ptr);
while(!WinAPI::folderExists(substr(_path,1,ptr)))
{
ptr = strfind(_path, '\\', ptr -1 , -ptr);
}
// ptr now points to last existing folder in the path.
//MKU: end
while (ptr)
{
WinAPI::createDirectory(substr(_path, 1, ptr));
if (!WinAPI::folderExists(substr(_path, 1, ptr)))
{
break;
}
ptr = strfind(_path, '\\', ptr + 1, strlen(_path));
}
return WinAPI::folderExists(_path);
}
Hi, it works for UNC path also.
Thanks,
/Ashlesh
//
static client public boolean createDirectoryPath()
{
int ptr;
FilePath _path = xinfo::directory(directorytype::Bin) + '\Image';
;
_path = strLRTrim(_path);
if (substr(_path,strlen(_path),1) != '\\') // Adding backslash gives a more simple while-loop!
{
_path += '\\';
}
//MKU: enables creation of UNC paths, by detecting which folder already exists (backwards).
ptr = strLen(_path);
ptr = strfind(_path, '\\', ptr, -ptr);
while(!WinAPI::folderExists(substr(_path,1,ptr)))
{
ptr = strfind(_path, '\\', ptr -1 , -ptr);
}
// ptr now points to last existing folder in the path.
//MKU: end
while (ptr)
{
WinAPI::createDirectory(substr(_path, 1, ptr));
if (!WinAPI::folderExists(substr(_path, 1, ptr)))
{
break;
}
ptr = strfind(_path, '\\', ptr + 1, strlen(_path));
}
return WinAPI::folderExists(_path);
}
Hi, it works for UNC path also.
Thanks,
/Ashlesh
Subscribe to:
Posts (Atom)