Friday, November 06, 2009

How to quickly set up Application Integration Framework (AIF) for testing Axd documents

Purpose of this post
Part of the test effort on our team at MDCC goes for verifying the Axd documents shipped with the Dynamics AX application.

As many people find it hard to setup AIF, I have tried to help them by creating an automated way of doing the initial setup, which can be used for testing the documents using a 1-box setup and FileSystem transport adapter.

Download link
From the following link, you will be able to download an X++ class that initializes all the entities required for AIF to work, like the endpoints, transport adapters and channels, services, their actions and action policies.
Note, that since I am working on the Inventory team, I am filtering out the services accordingly. You can easily extend/modify this to suite your specific needs by changing the filter or adding new ones in classDeclaration and method main

Download xpo

Example from the standard application
To give a specific example, I encourage you to try sending a selected item electronically in form of an XML file right after executing the job.
To do that, navigate to Inventory Management\Common forms\Item details and press Send electronically button. Fill in the values for endpoint, filter on a specific item(s), and press OK.

Your screen should look similar to this:


Processing the document
The document is successfully placed into the queue for processing and sending through the gateway. If you have a batch job for processing AIF services up and running, you will soon see a file in the outbound files folder setup on the outbound channel.
If you would like to learn, how to set up the batch jobs for this, follow the below link: Start and stop the asynchronous AIF services

In order to avoid having to set the batch jobs up, I have added 2 extra methods to the class for starting the processing of inbound and outbound messages.


public static void ProcessOutboundDocuments()
{
new AifOutboundProcessingService().run();
new AifGatewaySendService().run();
}
public static void ProcessInboundDocuments()
{
new AifGatewayReceiveService().run();
new AifInboundProcessingService().run();
}


Just call the DEV_AifInitialSetup::ProcessOutboundDocuments method from a job, and the document will be automatically processed and sent on its way to the outbound documents folder.

Output
The resulting XML file for the item should look similar to the following:

Monday, October 26, 2009

Mock objects implementation for AX

As you might now, I am working as a Software Development Engineer in Test at Microsoft Development Center in Denmark.

But the only real test framework that comes with AX is the SysTest framework (you can read more about it here).

Below you will find another framework for Dynamics AX, that was written by one of the members on my test team and allows to implement and use mock objects for testing the AX application.

More information and download link

It would be great if you could try it out and provide your feedback here or directly on the author's blog.

Thursday, October 22, 2009

Running a class from AOT or "How to assign a class to an action menu item?"

OK, so this might seem as a very simple question for many of you.

But, in reality, I still now and then meet people who have worked with AX for quite some time, but don't know this very basic concept.

Therefore, I just want to briefly describe it here to refresh everyone's memory

Apart from allowing to run the class from AOT, this will allow to assign it to a menu item (according to Best Practices, it should be a menu item of type Action), and run the class using this menu item.

Below is the correct syntax of the main method:


public static void main(Args _args)
{
//Your code here
}


Please also note, that there is an editor script that contains the template for the main method. You can invoke it from Scripts->template->method->main

Monday, September 28, 2009

New AX blog in da house

Most of you probably don't know Denis Fedotenko, but he is a well-respected member of the Russian AX community with multiple incredibly detailed articles about SCM functional areas.

He has recently started translating them to English and posting on his web-site, http://fedotenko.info/.

I highly recommend all of you to visit the link above and read the articles already posted there.

Tuesday, August 25, 2009

“Go to main table” on a RunBase dialog control

In one of my blog posts, I have been posed with the following question:

“how to achieve go to main table on dialog field.
for example a dialog is having a field of lookup custAccount, now what i need to have a go to main table functionality on the same.”

So, the short answer is: It is not possible to override jumpRef method directly on the dialog control. This is due to the fact that in order to show the “Go to Main table” link in the context menu of a control, you need to actually override that method on the form, which is later used to draw the context menu.

There are 3 possible ways that you can achieve the same functionality though, that I would like to briefly discuss here:

  1. Recommended Don’t bother with the dialog. Simply create a form, and override the jumpRef method on the needed control on the form. To demonstrate this behavior, you can use the Tutorial_RunBaseForm class and form. Override the jumpRef method, put the code to call the main form there. And you are done. Simple, and does not require a lot of coding. There is a lot of confusion, where junior AX developers think it will require a lot of code changes to replace a dialog with a form. This is not entirely that hard, as RunBase classes can use a regular AOT form instead of the regular dialog.
  2. Use controlMethodOverload approach, and create the controlName_context() method, which is executed when you try to open the context menu on the specified control. Inside this method, build the context menu from scratch. This way, only the items you want to be shown will be present in the context menu. Note: this means, that standard context menu items, like Setup, will not be shown in the menu (unless you add and handle them).
  3. Use controlMethodOverload approach, as in the previous example, but instead of overriding context() method, override the showContextMenu method. This will allow you to add your custom context menu items to the standard context menu. This does not seem to work on Axapta 3.0 though, and I did not try to figure out why. Note you need to uncomment some code in order to enable this approach (I left a TODO comment for that).

I have made the necessary changes, demonstrating the latter 2 approaches, using the class located under Classes\Tutorial_RunBaseBatch. You can download the xpo here (it contains only the USR layer changes).

The class used for drawing the context menu in the example is called PopupMenu. A good example of how this class can be used in the application is available in AOT under Forms\Tutorial_PopupMenu. Some information, along with another example, is available on MSDN.

A while ago, I have suggested some minor changes to the Dialog framework classes, which allow to simplify the process of overriding control event methods on the dialog. The original post can be found through this link: http://kashperuk.blogspot.com/2007/06/3-dialog-extensions.html

Let me know if any of this requires more clarification.

Monday, August 24, 2009

Inside Dynamics AX 2009 – Russian Translation

As you all know, Microsoft has recently released another book on development in Dynamics AX, called Inside Dynamics AX 2009.

For the past 2.5 months, I have been working on the Russian translation of this book, and now I am glad to say that the translation is over and will soon hit the shelves of online-stores. I guess it will also be available directly from Microsoft Russia, similar to the 4.0 version.

The book has gained a lot in weight :) and content. With more than 200 new pages, as well as many changes and updates of the existing chapters, the book is definitely a good investment. New “hot” features of Dynamics AX, like SSRS reports, Workflow, Role centers, etc., are described in the book from a developer point-of-view.

I really hope that my effort will not go in vain, and the book will be helpful to people working with Microsoft Dynamics AX 2009.

Thanks

Wednesday, May 20, 2009

Moving RSS from FeedBurner

Hi, subscribers. This is a small notification message.

Just wanted to let you know that I will be moving the RSS feed away from FeedBurner over the weekend, as it does not seem to work correctly with one of the MSDN pages, where my blog is being displayed.

So, instead of the following feed:
http://feeds.feedburner.com/KashperukIvan
you should use the one exposed on the blog:
http://kashperuk.blogspot.com/feeds/posts/default?alt=rss

If the problems with the MSDN page are solved, I will switch back to FeedBurner, but this won't effect you all, if you are using the latter feed link (as it is redirected automatically)

Thanks

Sunday, April 26, 2009

Lookup methods tutorial + custom list lookup implementation

One of the great features available in Dynamics AX is the support of lookup forms that provide a user-friendly interface for selecting a value for a field from a list, and are highly customizable, allowing the developer great flexibility in meeting user needs.

Recently, I was posed a question of how to present a user with a list of custom-defined values in a lookup form.

The simple (and suggested) approach here is to create a new BaseEnum, containing all the specified values, and add a ComboBox control for this enumeration to the form. If the values are to be displayed conditionally (only a subset is shown each time), you can build a superset of all values in AOT, and use SysFormEnumComboBox class to limit the actual output at runtime.

But, this would not work in my case, because the values in the list were dependent on other data in the form plus the current date. Using a temporary table for this scenario seemed like an overkill (but possible). So i decided to investigate the system class SysLookup for hints on how this can be done with minimum effort. The implementation of this method is provided below.

As part of posting this implementation, I decided to also briefly describe some of the other lookup method options available to an AX developer, turning this post into a small tutorial on lookup methods.

Tutorial_LookupMethods_Screenshot

1. The approach used most in the application is the implicit lookup based on table fields. As you can see from the control properties, DataSource and DataField specify which table field the control is based on. In my example, it is based on SalesTable.CustAccount, which uses the ExtendedDataType CustAccount, which has a relation to CustTable.AccountNum. Therefore, any time you add this field to a form, it will automatically provide a lookup button to select one of the customers.

Relations being specified on EDTs is at times confusing to people, who are used to seeing the relations between tables on the tables themselves. Technically speaking, such definitions on EDTs are incorrect. But no worries, AX supports the “correct” scenario out of the box as well. The relation to CustTable could have been specified on the table just as well.

2. 2nd most used approach is to specify the ExtendedDataType on the control directly. This is used to allow the user to specify a value to filter the records on directly from the form, for example (without the need to go to Extended Query form). It is also indirectly used on all RunBase dialogs in the system (when creating a DialogField, we specify the EDT to be used, which is transfered to the ExtendedDataType property on the corresponding control). In the tutorial, it is again the CustAccount EDT that is specified in the properties.

3. The 2 above examples both used metadata to define what lookup is to be displayed. The 3rd most used approach is relying on SysTableLookup class and builds the lookup at runtime. The code is relatively straightforward, and is described in more detail on MSDN. Using this approach, the developer can specify the query to filter the data being displayed in the lookup form. Note, that SysTableLookup only allows to have data from one table in the lookup form (+ display methods on this table). SysMultiTableLookup is an extension I have created a while ago, that adds this and other useful functionality to SysTableLookup class.

4. The remaining 2 standard approaches are rarely used in the application. Lookup based on ExtendedDataType is very similar to approach described under #2, but is executed from code at runtime. This way, you can change the lookup data displayed dynamically, based on some conditions (For example, on Ledger Journal lines, the offset account lookup shows vendors, customers, banks, etc. based on the offset account type specified on the line).

5. BaseEnum values are usually represented as a ComboBox (and, in special cases, CheckBox or RadioButton) control on forms in Dynamics AX. The lookup is provided by the kernel automatically for this type of control. But, sometimes, it is required to show the values of an enumeration in a string control – most common scenario is providing filter capabilities based on enums, where multiple values can be specified at once, similar to extended query form filters. In fact, this approach is actually used on SysQueryForm for enum fields. As you can see from the code, the lookup call is also very simple in this case.

6. This approach does not currently exist in the application, and the goals for its implementation were already described above. The lookup method code in this case looks rather straightforward, here it is:

public void lookup()
{
Counter yearCount;
List valueList = new List(Types::String);

for (yearCount = 0; yearCount < 5; yearCount++)
{
valueList.addEnd(strFmt("Year %1", year(SystemDateGet()) - yearCount));
}

SysLookup::lookupList(this, valueList, "List of years");
}

As you can see, the data displayed in this lookup depends on current system state (date) and other data (yearCount). It uses the class List to hold the values to be displayed.

You can download the project (Compatible with Axapta 3.0 – Dynamics AX 2009) with the tutorial and custom list lookup implementation by following the link below:

Note: The xpo contains changes to SysLookup class/form (only usr layer has been exported, for your convenience). Be careful when importing those, and don’t import them into the production environment.

Thursday, April 23, 2009

Be careful with join clauses when writing complex queries

Join clause evaluation is dependent on its position in the sql statement. In SQL Management Studio, if you try to specify the conditions incorrectly, you will receive the following error message:

SQLstatement

In X++, you will not receive any compilation errors, nor any runtime errors. In complex scenarios with a lot of queries, this might go unnoticed, and will be extremely hard to weed out at a later stage, when data inconsistencies crawl in.

Take, as an example, the following job. At first glance, the 2 methods look exactly the same, and it seems as if they should work just fine. But in reality, the second method will return incorrect results, because inventSum.InventDimId will be treated as a constant (empty string as the default value) and not as a table field used in the same select statement.

QueryBuild classes have a major advantage in this situation, as you cannot easily add join clauses (links) unless adding to the child (joined) queryBuildDataSource.

static void JoinClauseWarningJob(Args _args)
{
#define.ItemId("ESB-005")

void testCorrectJoin()
{
InventTable inventTable;
InventSum inventSum;
InventDim inventDim;

select inventTable
where inventTable.ItemId == #ItemId
join inventSum
where inventSum.ItemId == inventTable.ItemId
join inventDim
where inventDim.inventDimId == inventSum.InventDimId;

info(strfmt("Correct join where clause: %1", inventSum.AvailPhysical));
}

void testIncorrectJoin()
{
InventTable inventTable;
InventSum inventSum;
InventDim inventDim;

select inventTable
where inventTable.ItemId == #ItemId
join inventDim
where inventDim.inventDimId == inventSum.InventDimId
join inventSum
where inventSum.ItemId == inventTable.ItemId;

info(strfmt("Incorrect join where clause: %1", inventSum.AvailPhysical));
}
// Actually execute the code
testCorrectJoin();
testIncorrectJoin();
}

So, the suggestion is simple: Use QueryBuild classes (or AOT queries) whenever possible, and pay attention to the order of tables and join clauses in the select statements that you write.

Thursday, January 22, 2009

Microsoft Dynamics Convergence 2009 New Orleans

Well, I cannot start with any statement other than a quote by Steve Ballmer as of today. Of course, most of you have already read this one place or the other:


In light of the further deterioration of global economic conditions, Microsoft announced additional steps to manage costs, including the reduction of headcount-related expenses, vendors and contingent staff, facilities, capital expenditures and marketing. As part of this plan, Microsoft will eliminate up to 5,000 jobs in R&D, marketing, sales, finance, legal, HR, and IT over the next 18 months, including 1,400 jobs today. These initiatives will reduce the company’s annual operating expense run rate by approximately $1.5 billion and reduce fiscal year 2009 capital expenditures by $700 million. ...


Nevertheless, Microsoft Dynamics product line continues to grow, expand the feature set and customer base, and I am very confident it will have great success on the market in the future as well, even in the largest economy recession in many years.

Therefore, I would like to invite all of you to Convergence 2009, taking place March 10-13 in New Orleans, Louisiana, USA.
Microsoft Dynamics Convergence is one of the most exciting events in our business. It is an opportunity to listen to Microsoft plans for Microsoft Dynamics and related products, learn about all the possibilities your company can gain with these products, as well as meet with other business decision makers, Microsoft employees, and industry experts to gain knowledge, increase their understanding of Microsoft Dynamics business management solutions, as well as get some business insights how to thrive in the challenging economy.

Here are some links to get you started:

The
session catalog (containing 225 sessions) is now live on the Convergence marketing site.

The Complete Guide to Convergence for Partners (PartnerSource access is required to access this link) is a valuable planning resource on PartnerSource. There are tips, tools and templates to help partners create the most worthwhile Convergence experience for their company and their customers’ companies.

I hope that many of you will be able to attend, and have a fun time there.

Tuesday, December 16, 2008

Supply Chain Management in Dynamics AX - a new Microsoft blog

For quite some time now, the MDCC (Microsoft Development Center Copenhagen) team has been nurturing the idea of launching our own blog about the Supply Chain Management area in Microsoft Dynamics AX.

And yesterday, it finally happened!
We posted the first article about Quality Management upgrade process for TQM solution (by Fullscope) users.

http://blogs.msdn.com/DynamicsAxSCM
http://blogs.msdn.com/DynamicsAxSCM

I recommend all of you to add this link to your favorites, as we plan to post on a regular basis, and about things important to all of you. That said, I would like to invite all of you to post article ideas or questions related to Microsoft Dynamics AX SCM modules as comments to this message or directly on the SCM blog. We, in turn, will try to cover those in our blog posts.

Thursday, December 11, 2008

Tool for protecting your Dynamics AX source code

"Is there a way to protect/hide my X++ code?"
People asked me this question a million times by now.

To most of them, I described 2 possible ways to go, that I know of:
- Do not share the source code, but instead provide the customers with an AOD file.
- Use a tool that would produce obfuscated code out of your modifications.

Both ways are not perfect, of course. If you provide the code as an AOD file, you need to be sure that the customer does not have X++ license. If you provide obfuscated code, the customer developers (if they are present) will have a hard time interacting with your code. And, eventually, both ways leave the customer at a disadvantage. As soon as the vendor is not there to support (provide fixes in terms of an updated AOD file or XPO with obfuscated code) them for whatever reason, the customer has no way of supporting the add-on solution on their own.

But this post is not about the cons of trying to protect your code.
It's about the possibilities. Today, finally, I can support my previous suggestion #2 with an actual link to such a tool: Next Innovation Code Scrambler Homepage

Here is a screenshot of how the code looks after Code Scrambler is finished with it:


Note, that the tool is not free, and I have not actually tried it out.
But there is a sample project showing the resulting scrambled code. You can download it for a first impression, and contact the company if you are interested in the tool.

Another note - this is not an advertisement, I am not in any way related to Next Innovation Company.

Thursday, November 20, 2008

Personal Experiences with Live Mesh

This post is not going to be about Dynamics AX. It will be about a software product I was thrilled by so much I would like to share it with all of you.

I won't post a detailed description of the product here. You can read that yourself at www.mesh.com. But here is a brief introduction, just to give you a basic idea of what the software can bring into your life.

WHAT IS LIVE MESH?

With Live Mesh, you can synchronize files with all of your PCs (and soon your WM6 phone and Mac as well), so you always have the latest versions handy. Access your files from any device or from the web, easily share them with others, and get notified whenever someone changes a file. Working on one computer, but need a program from another? No problem. Use Live Mesh to connect to your other computer and access its desktop as if you were sitting right in front of it.

Here is a screenshot of the web interface for managing your devices in the mesh:


What I would like to share with you is the personal experiences I had using this software for a month now. In 1 word - fantastic. Live Mesh is still in Beta, but already I can tell you - simplicity is the word. You set it up (takes 5 minutes and is very simple, all you need is a LiveID, which I hope all of you already have). And that's it, you are done. And from then on - it just works. Great!

And here are 2 screenshots of how I use Live Mesh in my everyday life.
Obviously, I have all of my computers meshed, available to me when I need them (they need to be turned on, and have access to internet, of course).



And so far I have 4 folders in the mesh, and I would like to discuss each of them separately:


Personal - I store a backup of my personal data in this folder, which is synced across all my PCs, so that I have it at hand in case I need it. Plus, I have my Personal OneNote workbook in there, with all info I need.
Favorites - Favorites are not synced accross all my PCs, providing the same list on all of them in IE. This is great. This was a feature most of the browsers tried to implement throughout multiple releases. And here it is, as easy as it gets. Any time I bookmark a page, all my other browsers get this page bookmarked as well.
Incoming - this is the folder for file transfer between PCs. Now I don't have to send it to my e-mail every time I need a document scan or something. And, I invite other people as members of this folder, sharing pictures and other documents with them. That easy. And, they get updates every time I add a file, without me having to notify them.
Work - This is my work folder, which I don't sync to my home PC (you can see it is a ghost folder on the screenshot). Any file I work on is automatically synced between my work PCs, so I have an up to date file any time I access it. Extremely efficient.

Well, that's about it. Now, all you have to do is go and try it out yourself.
Have fun!

Friday, October 17, 2008

TableBrowser.NET (a small .NET BC tutorial)

Here is a Visual Studio solution, demonstrating how the Dynamics AX database can be queried through the .NET Business Connector, and how the results of this can be presented to the user in a user-friendly manner.

Here is a screenshot of how it looks:


You can download the solution on axaptapedia.com.

The class to investigate in the solution is the DynamicsAX class. It provides a pretty good interface for reading data out of Dynamics AX.

After opening the solution, make sure to replace the BusinessConnectorNet.dll, pointing it to your AX installation path (if it is not in GAC)

Tuesday, October 07, 2008

The future of programming languages or Anders Hejlsberg/Steve Ballmer Tech-Pep-Talk

Sunday, September 28, more than 350 IT-professionals from the entire country (Denmark) came to MDCC (Microsoft Development Center Copenhagen) to get a 90-minute TechTalk from Anders Hejlsberg and a 15-minute PepTalk from Steve Ballmer.

Click here to see the video.

Wednesday, September 24, 2008

Microsoft Dynamics AX 4.0 data model overview

I have great news for you, readers :)
Recently, on an internal Microsoft discussion group, I received a nice document with an overview of the data model for Dynamics AX 4.0.
After permission was received to publish this document to an external audience, I uploaded it to my personal web-site, so that all of you can download it at a convenient time.

The link is below. Enjoy!

Download AX40datamodel.doc (4.41 Mb)

UPD: A newer version of this document does not exist, so I won't be able to post it here

Monday, September 22, 2008

SysMultiTableLoookup - dynamic lookups based on multiple tables

Wow! MSDN for Microsoft Dynamics AX is getting better every day. This is terrific news!! I still remember the days, when all the information was extremely hard to find. It had its own charm though :)
Anyway, this topic is really not about MSDN. It is about lookup forms.

First of all, for the record: I (and the Best Practices document as well) recommend creating custom lookup forms in AOT instead of dynamically coding them in the overridden lookup methods on controls/datasource fields.
But, in reality, this is true only for lookup forms with very large complexity. I won't go into a discussion of why that is the way it is here. :)

Now, back to what I was planning to write about:
In order to build a lookup form from code, developers use the SysTableLookup class.
You can go to MSDN (mentioned above) to read a How-to article on creating a run-time lookup form, as well as take a quick look at the SysTableLookup method descriptions.

SysTableLookup class has evolved over the multiple releases, providing more and more flexibility and control to the application developers.
I would like to publish another extension to this class, SysMultiTableLookup, which I hope will prove useful to members of the AX community.

Short list of features:
- Backward compatible, should cover everything that is present in AX 2009 version of SysTableLookup class
- Allows including multiple tables into lookups with different join types
- Completely based on the Query that you build, no extra parameters (except for the control) are needed to initialize the class
- Allows adding aggregated fields to the lookup
- Displays fields based on Boolean Enum as check boxes
- Allows to specify alternative labels when adding fields to the lookup

You can download the project from axaptapedia.com.
It has (to some extent) been tested on Axapta 3.0 SP3, AX 4.0 and AX 2009.

Also included in the project is a tutorial form, showing 4 examples of dynamic lookups using the new class. After importing the project, make sure to try out the form, and use it for future reference for code examples and other inspiration.

Tuesday, September 16, 2008

SysInfoAction class description - Improve your Infolog

In the last couple of weeks I have been asked about this a number of times, so I decided it would be a good idea to describe what the class can do for you.

In just a few words, this class helps you interact with your users better, helping them perform some desired action (predefined) on request. This will save some time for the user, providng for a better user

There is a number of classes already present in the system.
Just to name a few used the most:

JournalInfoAction - allows navigating to the specified journal line. This is used, for example, when checking the journal lines before posting.
SysInfoAction_Editor - opens the editor in the specified method on the specified line/column. Primarily used for development purposes.
SysInfoAction_FormRun - opens a specified form, setting focus to a specific control, if required. There are many extensions of this class, allowing for more control over what is to happen.
SysInfoAction_MenuFunction - same as the one above, but the input is a menu item that is to be launched on user action.
SysInfoAction_newWindow,SysInfoAction_AOTproperties - both are used to ease up the dev's life a bit. The first one opens the specified AOT object in a new window, the latter one - the properties for the object.

And so on...

I had to create one extension of this class yesterday as well, while doing a small tool we use inside our team. The requirements were to launch a specific external application, specifying a number of files as command-line arguments. WinAPI ShellExecute can do exactly that. So I create a simple wrapper around the WinApi::ShellExecute method that is accessible as an infolog action.

Here is an example of how this class can be used:



You can download the class from axaptapedia.

The output of the infolog, in this case, would look similar to this:

Infolog output


One other thing worth mentioning about these classes is the method infolog.infoActionObject(). This is not used as often, but provides a greater control over the infolog action by allowing interaction with an open object, like a form.
This is used in AX journals (Inventory Transfer journal, for a specific example, if you wish). Whenever you check the lines of the journal (before posting), you get an infolog in case of errors, which allows to navigate to the specific line with the error. The navigation occurs in the journal lines form currently open, which is much better than opening a new form for each line.
In order to use this, simply specify the object that needs to be available when executing the infolog action, using the method mentioned above, like the following:

infolog.infoActionObject(this); //if called from the method on a class/form, for example

For more information, check out the article on Axaptapedia (I hope it will get expanded over time :))

Tuesday, August 12, 2008

Another useful Editor Script for developers

In AX the principle of upcasting is used quite a lot. Some examples coule be the RunBase hierarchy or the InventMovement class hierarchy. Basically, the base (or super) classes contain the main part of the hierarchy logic, while subclasses only override a couple of methods performing actions specific to this class.

When browsing the AOT, trying to find a specific line of code (debugging without the debugger, basically), you often find yourself in a situation when you lookup a definition of a method from a derived class, and end up in this method of the base class instead (because upcasting was used in the code in question). And every time you need to see the same implementation in the child class, you need to go back to the AOT and open it from there manually.

Well, not any more.
Here is a small editor script, that you can use to navigate to an overridden method of a derived class.

I created 2 versions of the same script, one using xReferences, the second using Dictionary class. The xRef one, generally, works faster once the xRefs for the class hierarchy is updated (happens the first time you use the script). So I am not posting the second script version. If anyone is interested in that version specifically, let me know and I will send you the code.

I made a couple of small changes to the script since my previous post (which I deleted), making it possible to import the script without compilation errors into AX prior to verion 2009. Sorry for that :)

You can copy-paste the code for the script from axaptapedia.com (There is a problem with copying over the code from blogger site directly)

You can read more about Editor Scripts and how to use them here

Enjoy, and get back to me with any comments or suggestions, posting them as comments or e-mailing me directly

Thursday, July 10, 2008

Microsoft Dynamics AX 2009 Keyboard shortcuts

A whole lot of new and handy shortcuts have been introduced in Microsoft Dynamics AX 2009. To name just a few, that are very important for developers:
Ctrl+Shift+P opens the Projects
Ctrl+Shift+I (from AOT or projects) opens the import project window, etc.
Alt+F1 will return you to the main Dynamics AX window (especially useful for those fond of Tabax)

A fellow tester from Dynamics AX Client team, David Kidder, created a document containing the shortcuts available, grouping them according to where they are used in the application.

One thing I would like to highlight is that you don't need to work for Microsoft to create this list. You can get the list of all available shortcuts in the system by launching the client (Ax32.exe) with the -internal=GENERATEKEYHELP command line argument. The xml file with the shortcuts, AxKeyDump.xml, will be placed into the Client\Bin folder of Dynamics AX.

It is an extremely useful document, and I suggest everyone prints it out and hangs it by their desk.
The download link can be found below:
AX 2009 Keyboard Shortcuts.docx

Warning: The file is in Microsoft Word 2007 format, but I am sure all of you have that (or the converter) by now.

Tuesday, July 08, 2008

AX 2009 RTM Demo Data released

Finally, the new demo data for AX 2009 has been released. Partners and Customers can download it now from the links below:
Partner Source - download (Requires partnerSource login)
Customer Source - download (Requires CustomerSource login)

You will find two different data sets:
Contoso Base: Contoso base demo data, with almost no transactional data
Contoso Trans: Contoso transactional demo data, with 2 years of transactional data from Jul 1, 2006 to Jul 1, 2008 for some modules.

Demo Company Overview

The Demo Data set for Microsoft Dynamics® AX 2009 is no longer based on the Global Trade and Manufacturing Company. Based on market feedback we have created a new Contoso Entertainment systems group of companies. It comes with 2 fiscal years of transactional data that enable us to demo our stronger Business Intelligence story and Role Center pages, while allowing us to easily expand the demo data story in future releases as we expand Microsoft Dynamics® AX’s functionality footprint.
Contoso Entertainment Systems (CES) is a home electronics manufacturing, distribution and retail company that includes a Professional Services department. Its headquarters are in the USA with a key distribution subsidiary based in Germany and it works with the relevant currencies. CES distributes televisions, projectors, Digital Video Recorders and Players, and audio receivers. It manufactures speakers and assembles home theatre systems. CES’s customers are primarily based in North America and Europe and include Major Accounts (such as hotel chains), Wholesalers (of differing sizes), Retail stores (that are self-owned and operated), as well an internet storefront.
The legal and physical structure of CES is setup as follows:
• CEC – Contoso Entertainment Consolidation, based in USA
• CEU – Contoso Entertainment USA, Headquarters based in USA
o Site 1: Production of all speakers
o Site 2: Assembly of home theatre systems and Services
o Site 3: Production of Standard speakers
• CEE – Contoso Entertainment Europe, Distribution subsidiary company based in Germany
o Site 4: Distribution, Assembly and Service of all products
• CVC – Virtual company that includes table collections from CEU and CEE.

The downloads for Contoso Entertainment Systems demo data offers transactional data for Basic, Administration, General Ledger, Bank, Fixed Assets, Accounts Payable, Accounts and Receivable, Inventory Management, Intercompany, Production, Master Planning, CRM, Project, Expense Management, and Human Resources modules, and is intended to demonstrate these modules’ functionality. It also offers base data (i.e. no transactions) for the Product Builder modules. There is no demo data available for Payroll and Cost Accounting modules.

A lot of work has been put into these demo data files, to allow the users to investigate most of the functionality of the applicaton.
Thanks for this.

P.S. Just received some more input on the dataset, so decided to edit the message and post this interesting info as well

Thursday, May 29, 2008

EditorScripts.addIns_OpenInAOT - version 2

A long time ago, I posted an editor script for opening objects selected in the editor in AOT (link to that post)

Yesterday, miklenew from AxForum posted an editor script for AX 3.0 that opens a new AOT window with the object currently selected in the Editor, that works a little differently and also allows to open objects based on variable type. You can view the original post here.

Today I modified this code, extending it a bit and adding support for Dynamics AX 4.0 and Dynamics AX 2009 (For version 3.0 use the code posted on AxForum).

public void addIns_OpenInAOT(Editor e)
{
#AOT
TreeNode treeNode = TreeNode::findNode(e.path());
xRefTmpReferences xRefTmpReferences;
Column nCol = e.columnNo() + 1;
Line nLine = e.currentLineNo() + 1;
;
treeNode.AOTmakeXref(1);
xRefTmpReferences = xRefCreate::makeTmp(infolog.lastxRef());

select firstonly xRefTmpReferences
order by Column desc
where xRefTmpReferences.line == nLine &&
xRefTmpReferences.Column <= nCol;

if (!xRefTmpReferences)
return;

treeNode = TreeNode::findNode(xRefTmpReferences.path());

if (treeNode)
treeNode.AOTnewWindow();
}


As you can see, the code is very simple and utilizes the xReferences.
But the great thing about it is that updating the cross references is not required for this code to work, as it updates them on the fly for this specific AOT node.
I think this is a must have method for each application developer out there. :)

Tuesday, May 13, 2008

AxPaint / AxAssist for Axapta 3.0, AX 4.0 and AX 2009

First of all, I would like to remind anyone interested of what AxPaint is. This is a small activeX component + a small xpo, that will allow you to change the background image of your application to whatever image you like.
You can find installation instructions, screenshot and a more detailed description through the link below:
http://kashperuk.blogspot.com/2007/06/axpaint-make-your-dax-look-cool.html

Well, the tool has recently been updated with support for all versions of AX starting with version 3.0.
The download link for the new (and, most probably, final) version of this tool is AxPaint.
Enjoy! :)

Also, it is hard not to mention another development tool from the same author, AxAssist. Sadly, it is not free, but it is still worthwhile to check it out - maybe that's something you company would be interested in buying. There is a Trial version you will be able to play around with for 30 days. The homepage for the tool is - www.axassist.com

Monday, April 28, 2008

SysFormEnumComboBox - class allowing to show only some of the values for a comboBox

In Microsoft Dynamics AX 2009, a new class has been created, that got my attention recently after yet another question about this sort of thing was asked by a fellow Dynamics AX developer.

Often enough, we need to restrict the user selection from a particular ComboBox. Creating a new BaseEnum specifically for this purpose is a really cumbersome solution, which later might lead to problems of maintenance.

Originally, the SysFormEnumComboBox was designed to be used on forms to provide for this behavior. I modified the class slightly to allow for usage in RunBase Framework classes.
To demonstrate, how this class can be used, I modified the tutorial_RunBaseForm class and form, showing both scenarios: adding the control from the dialog method of the class, as well as adding it manually in the form design and methods.

To use this class, you need to know only one static method:

public static SysFormEnumComboBox newParameters(
FormRun _formRun,
int _comboBoxControlId,
enumId _enumId,
Set _allowedEnumValuesSet,
Form _form = null)

And here is an example of how you would use it:
sysFormEnumComboBox = SysFormEnumComboBox::newParameters(element, 
control::ComboBoxOnForm,
enumnum(InventTransType),
enumSet);

which means that the control ComboBoxOnForm will be bound to BaseEnum InventTransType, containing only values, found in the Set enumSet.

You can download the project for versions 4.0 and 2009 of Microsoft Dynamics AX through the following link:
download

P.S. It is also worth mentioning, that this class does not provide support for grids. It requires a stand-alone control, not bound to a database table field.

Wednesday, March 26, 2008

Microsoft Dynamics AX 2009 CTP3 release is available on PartnerSource

Finally, the CTP3 release is available for download from PartnerSource.

It is, as usual, a VPC image that you can install on a standalone computer.
Be warned, that the size of the image is huge - about 7 Gb in 3 parts.

Here is a short description of the toolkit:


The Demonstration Toolkit for Microsoft Dynamics AX 2009 Pre-Release (CTP3) contains marketing materials, demonstration scripts, and a Virtual PC image containing a full installation of Pre-Release of Microsoft Dynamics AX 2009. You can obtain the Demonstration Toolkit on DVD from a Microsoft Dynamics Partner, or you can download the contents of the DVD using the links on this page.


Download link (Requires PartnerSource access)
It would be very interesting to hear any comments you might have about the CTP release, as well as about any major (and minor, as well) bugs you might find in this PRE-release. Feel free to e-mail me or leave a comment under this post.


P.S. (One day later)
An ISO image was also made available today. It is much lesser in size, and is an image of the installation CD + licence file for CTP3 release.
Download link (Requires PartnerSource access)

Friday, March 14, 2008

AxForum in English / AxForum auf Deutsch

There was a blog post recently about using Google Translate! to read posts on AxForum, one of the best communities there is on Microsoft Dynamics AX.

Here is the direct link to AxForum translated from Russian to English with Google Language Tools (Google might think you are a virus, so you in some cases will have to input a verification line to continue)

What I would like to point out and promote here, is the fact that AxForum actually has support for User Interface in English and German, and sub-forums in both languages:

AxForum in English
AxForum in German (auf Deutsch)

There aren't many posts there at the moment, but all AxForum members would be glad to help anyone who posts a question in one of these sub-forums (if they know that language, of course). So don't be shy and visit the sub-forums when you are in doubt or have a problem you cannot solve on your own.


You can find the original post about Google and AxForum here

Monday, March 10, 2008

Microsoft Dynamics AX 4.0 Service Pack 2 is available for download

Just a short announcement today:

The Demonstration Toolkit for Microsoft Dynamics™ AX 4.0 Service Pack 2 (SP2) contains marketing materials, demonstration scripts, and a Virtual PC image containing a full installation of Microsoft Dynamics AX 4.0 SP2.

Download link (Requires PartnerSource login access)

P.S. Just a warning for anyone unaware - the VPC image is very large, as it cotains an operating system, SQL server, AX install with demodata, etc., total size exceeding 9 GBs)

Saturday, March 08, 2008

Hotkeys and Find vs Filter in Dynamics AX 2009

In Microsoft Dynamics AX 2009 a number of changes regarding Filtering in grids were introduced. I would like to talk about one of them today.

As most of you know, in AX 4.0 the Ctrl+F hotkey was replaced with Ctrl+K, which was very confusing for customers that were using AX 3.0 at the time. (see one of my previous posts with a .dll go fix that)

Well, I am happy to tell you, that Ctrl+F is now back as a regular (not Global) Find option in AX 2009. But Ctrl+K is also available. So it was decided, that having to identical commands is not really smart. So now they actually perform different actions.

Ctrl+F is Find
Ctrl+K is Filter = Filter by Field from the context menu on the grid line.

Now, you might wonder what the difference is. I will explain it on an example:

You have a grid with items of different Item Type (BOM, Item, Service) and different Item Group (Parts, Bulbs, etc.)

Scenario 1: (Notice the dialog caption is Filter)
1. Press Ctrl+K on Item Type "BOM"
2. Press OK (the value BOM is already inserted in the search field).
3. Only BOM items are shown
4. Press Ctrl+K on Item Group "Parts"
5. Press OK (the value Parts is already inserted in the search field).
6. Now only BOM items with Item Group = Parts are shown.

Scenario 2: (Notice the dialog caption is Find)
1. Press Ctrl+F on Item Type "BOM"
2. Input "BOM" and press OK (you have to input the value you are searching for every time).
3. Only BOM items are shown
4. Press Ctrl+F on Item Group "Parts"
5. Input "Parts" and press OK.
6. Now only items with Item Group = Parts are shown, including both BOM and other Item types.
So, basically, all previous filtering on the grid was removed before applying the new search criteria.

As a side note, I would also like to mention, that some changes were made to hotkeys in the Editor: Now, Editor Scripts are opened using Alt+R hotkey, instead of Alt+M, as in previous AX versions. (Alt+M was reserved for the global menu toolbar, which is one of the new features in AX 2009 as well)

Find all reports with datasources innerjoined 1:n

I haven't really written much X++ code in the past 5 months, so a work-related task on X++ was like a holiday :)

I needed to find all reports, in which there is a child datasource (on some level) that is inner joined with the parent datasource as 1 to many.

Here is one of the possible solutions of the problem.
I would also want to talk a little bit about different methods used in this scenario, in case some of you are still unfamiliar with those:

static void FindReports(Args _args)
{
#AOT
Report report;
TreeNode treeNode = TreeNode::findNode(#ReportsPath);
TreeNodeIterator iterator = treeNode.AOTiterator();
QueryBuildDataSource qbds;

boolean find1nInnerJoin(QueryBuildDataSource _qbdsParent)
{
int i;
QueryBuildDataSource qbdsChild;
boolean ret;
;
for (i = 1; i <= _qbdsParent.childDataSourceCount(); i++)
{
qbdsChild = _qbdsParent.childDataSourceNo(i);
if (qbdsChild)
{
if (qbdsChild.joinMode() == JoinMode::InnerJoin && qbdsChild.fetchMode() == QueryFetchMode::One2Many)
return true;

if (qbdsChild.childDataSourceCount() > 0 && find1nInnerJoin(qbdsChild))
return true;
}
}
return ret;
}
;

treeNode = iterator.next();
while (treeNode)
{
if (treeNode.sysNodeType() == 202) //Report
{
report = treeNode;
if (report && report.query().dataSourceCount() > 1)
{
qbds = report.query().dataSourceNo(1);
if (find1nInnerJoin(qbds))
info(report.name());
}
}
treeNode = iterator.next();
}
}


Here are some keypoints:

1. Notice the use of TreeNodeIterator class. This is an example of an Iterator applied to the AOT. Very convenient and easy to use. You can read more about this class and its methods on MSDN

2. Notice the use of BaseEnums QueryFetchMode and JoinMode - I have seen many developers specifying integer values instead. I would suggest using these enumerations instead - the code will be much easier to read later on.
I don't know the enum for return value of method treeNode.sysNodeType() though. So if someone does, write a comment - it would be nice to know.

3. Notice the use of an implicit conversion from a base type object (TreeNode class) to a derived type object (Report). This is allowed, because, as you know, X++ type system is a "weak" type system. But beware, because this might lead to run-time errors. For example, if you call a method on the Report class, that is not inherited from the TreeNode class, you must be absolutely sure that the object is actually of type Report. Otherwise, you will get a run-time error.
This is why before the conversion, I verify that only Report objects get through to the following code.

4. The last, but not least: Notice the methods exposed by the QueryBuildDataSource class - basically, it allows to receive a lot of information about a specified query. Again, for more information, refer to MSDN

Saturday, February 02, 2008

A not-so-easy game about Earth

Here is a fun game that challenges your brain. It's not really about AX, but can drive you crazy as well :)
I am still stuck on level 9, and it turns out there are so many places I haven't even heard of, not mentioning actually placing them on the world map. Very entertaining!


Thursday, January 17, 2008

Creating and Posting Inventory ProfitLoss journals in DAX using .NET Business Connector

Yesterday, I was helping a friend from Canada create a small solution that would create and post ProfitLoss journals in Microsoft Dynamics AX 4.0 using .NET Business Connector.

In the end, we created 2 solutions - one was entirely written in X++, and only simple class static method calls were made from C#. The other was completely written in C#, using various classes, available with .NET business connector.

I uploaded the solution to the following link, in case anyone would be interested to download it and play around with it or use in their projects.
Download ProfitLossPostingAppl

Also, here is the source code - it is a small console application, and I tried to add as many comments as possible, so that even complete X++ beginners would be able to easily read the code.

Notice that in the solution, there is a reference to the business connector dll.
You can find the Microsoft.Dynamics.BusinessConnectorNet.dll in the Client\Bin folder of your Dynamics AX installation. This dll is what provides you with access to the Dynamics AX application and the set of classes to use AX tables and classes.

using System;
using Microsoft.Dynamics.BusinessConnectorNet;

namespace ProfitLossPostingAppl
{
class AxProfitLossPostingEngine
{
static void Main(string[] args)
{
Axapta ax = new Axapta();
// company name, language, object server, configuration
// this uses Windows Authentication
ax.Logon("cmul", null, "localhost", null);

try
{
// Start a transaction
ax.TTSBegin();

// AxaptaRecord is a class that allows to work with Tables in AX
AxaptaRecord header = ax.CreateAxaptaRecord("InventJournalTable");
AxaptaRecord journalName = ax.CreateAxaptaRecord("InventJournalName");
AxaptaRecord line = ax.CreateAxaptaRecord("InventJournalTrans");
AxaptaRecord inventTable = ax.CreateAxaptaRecord("InventTable");
AxaptaRecord warehouse = ax.CreateAxaptaRecord("InventDim");

// You can call static table methods using the following syntax
journalName = ax.CallStaticRecordMethod("InventJournalName", "find", "IPL") as AxaptaRecord;

// There is a set of predefined methods on the AxaptaRecord class, like the clear(), initValue, DML operations, etc.
header.Clear();
header.InitValue();
// You can call table object methods as well, not only static
header.Call("initFromInventJournalName", journalName);
header.Insert();

line.Clear();
line.InitValue();
line.Call("initFromInventJournalTable", header);
// You cannot use table fields directly as in X++. Instead you have set/get methods
line.set_Field("itemId", "B-R14");

// Instead of using static table methods (like find) you can execute a direct SQL statement and receive the result in the AxaptaRecord object
inventTable.ExecuteStmt("select * from %1 where %1.ItemId == 'B-R14'");
// If you receive more that one record you can iterate through them using Next (as in AX)
line.Call("initFromInventTable", inventTable);

line.set_Field("Qty", 160.0);

warehouse.Clear();
warehouse.set_Field("InventLocationId", "MW");

warehouse = ax.CallStaticRecordMethod("InventDim", "findOrCreate", warehouse) as AxaptaRecord;

line.set_Field("InventDimId", warehouse.get_Field("inventDimId"));
line.Insert();

// Notice AxaptaRecord is passed by reference here
ax.CallStaticRecordMethod("InventJournalTable", "initTotal", header);
header.Update();

ax.TTSCommit();

// You can call static class methods the same way you call table static methods, but using a different method on Axapta class
// So in case you wrote the posting in X++, you would be able to call it, passing the JournalId as the argument
// int numOfLinesPosted = (int)ax.CallStaticClassMethod("DEV_ProfitLossEngine", "postProfitLossJournal", header.get_Field("JournalId"));

// Or, you can use the AxaptaObject class to accomplish the same from C#
// You can initialize a new class using the Axapta class method
// AxaptaObject journalCheckPost = ax.CreateAxaptaObject("InventJournalCheckPost");

// Or using a static method, if that suites your needs better
// Notice here that an object of type AxaptaRecord is passed into a method that expects InventJournalTable as the argument
AxaptaObject journalCheckPost = ax.CallStaticClassMethod("InventJournalCheckPost", "newPostJournal", header) as AxaptaObject;
// You can object methods the same way you would on a table
journalCheckPost.Call("parmShowInfoResult", false);
journalCheckPost.Call("parmThrowCheckFailed", true);
journalCheckPost.Call("parmTransferErrors", false);

journalCheckPost.Call("run");
int numOfLinesPosted = (int)journalCheckPost.Call("numOfPostedLines");

Console.WriteLine(String.Format("{0} line(s) have been successfully posted", numOfLinesPosted));
Console.WriteLine("JournalId is " + header.get_Field("JournalId"));
Console.WriteLine("Press any key to continue ...");

ax.Logoff();
}
catch (Exception ex)
{
ax.TTSAbort();
ax.Logoff();

Console.WriteLine(ex.Message);
}

Console.ReadKey();
}
}
}



P.S. Of course, it would probably be a better idea to use classed InventJournalTableData, InventJournalTransData, etc.
But for the simplisity of the example, everything is done directly with tables.

Wednesday, January 16, 2008

Microsoft Dynamics AX 2009 - some of the new development features

Alexei Eremenko from Microsoft Russia has posted a number of articles about the new features that will be available in DAX 2009.
The original link, which is in Russian (but the main thing to look at is the code, which is universal): http://blogs.msdn.com/aeremenk/archive/2008/01/15/7118429.aspx

I would like to make a brief review of the features he talked about for the English-speaking population and another feature I liked that Alexei did not mention.

Let's start with the support for union in SQL statements (but only when using Query* classes).


query = new Query();
query.queryType(QueryType::Union); // The other value of QueryType is "Join"



Another Exception type has been introduced, which now actually allows to catch the DuplicateKey exception:

Table t;

try
{
while select forupdate t
{
test.Field1 = ‘xyz’;
t.update();
}
}
catch ( Exception::DuplicateKeyException, t )
{
infolog(‘Record already exists - ‘ + t.Field1 );
}



The bulk DML statements now allow using inner/outer joins, and you can access the result of the update_recordset operation to get the number of rows that were updated:

update_recordset batchJob setting
Status = BatchStatus::Canceled,
EndDateTime = thisDate,
Finishing = 1
where batchJob.Status == BatchStatus::Cancelling
notexists join batch
where (
(batch.Status == BatchStatus::Ready ||
batch.Status == BatchStatus::Executing ||
batch.Status == BatchStatus::Hold ||
batch.Status == BatchStatus::Cancelling)
&& batch.BatchJobId == batchJob.RecId
);

rowsUpdated = (batchJob.RowCount() > 0); // get the number of updated rows with rowCount()



And, the feature I enjoyed, is that we now have crossCompany support in X++. Meaning you can access data from tables from a number of companies in one query.
Here are code snippets to explain what I mean:

static void DataBaseAccess_CrossCompany(Args _args)
{
InventTable inventTable;
container companyContainer = ['IN1', 'QMS'];
;
while select crossCompany : companyContainer inventTable
where inventTable.ItemId == "B-R14"
{
print inventTable.ItemId, " -- ", inventTable.dataAreaId;
}
pause;
}



This code will print ItemId from 2 companies, even though InventTable has the property SaveDataPerCompany set to Yes.

The same functionality is available with the Query classes:

static void DataBaseAccess_CrossCompany_Query(Args _args)
{
Query query = new Query();
QueryBuildDataSource qbds = query.addDataSource(tableNum(InventTable));
QueryRun queryRun;
InventTable inventTable;
;
qbds.addRange(fieldNum(InventTable, ItemId)).value(queryValue("B-R14"));

query.allowCrossCompany(true);
query.addCompanyRange("IN1");
query.addCompanyRange("QMS");

queryRun = new QueryRun(query);
while (queryRun.next())
{
inventTable = queryRun.get(tableNum(InventTable));
print inventTable.ItemId, " -- ", inventTable.dataAreaId;
}
pause;
}



If you don't add any specific company ranges, the data will be retrieved from all companies you have access to.

Microsoft Dynamics AX 2009 has a lot more to offer, of course. But enough for today.

Tuesday, November 20, 2007

Inside Microsoft Dynamics AX 4.0 in Russian

This entire week is actually special.

The Inside Microsoft Dynamics AX 4.0 book will very soon be available in Russian.
I was the one helping with the translation.
I am now finished with all 18 chapters with just some minor corrections left to other parts of the book.
So I will try to get back to posting about AX very soon.

Next week, on Tuesday (November 27th) Moscow will be hosting an annual Microsoft Technical Event.
You can read more about it on http://platforma2008.ru/ (Russian language only)
The new book will be presented there, so make sure and visit if you can.

Microsoft Dynamics AX Community recognition :)

Today is a special day for me. And for the community as well, I hope :)

I was replying to one of the posts on the community and noticed, that now I have a bronze medal near my name.

Here is what it means:
http://www.microsoft.com/wn3/locales/help/help_en-us.htm#Levels
(it means I had 51 replies marked as Answers)

Saturday, October 20, 2007

List panels in Dynaics AX - a short description of SysListPanel class

SysListPanel class – what is it?


Whenever a user needs to select a number of values from a certain list, so that the selected list gets processed and saved, a list panel can be used. Another use of this type of control is when you are assigning certain properties/options to a specific object.

A good example is the “Administration\Users” form, where each user is assigned to one or more user groups, giving him certain access to DAX functionality.

Here is how it looks:


SysListPanel is the basic class for a large hierarchy of classes showing different list panels throughout the application.

The hierarchy tree for this class is shown below (DAX 4.0 SP2):

One important thing you need to understand when working with list panels – the class is not enough. :) When there is a class, there is a form, containing the list panel and using this class. But, of course, the class is responsible for most of the things happening when a user works with list panels.

SysListPanel or SysListPanelSet – which class to use?

When I consider, what class to extend when creating a list panel on a form, I start off by figuring out how the selected data is going to be stored. If the data selection is supposed to be reflected in the database (for example, when we add the user to a user group, a record is created in UserGroupList table), then extending from SysListPanel should be your choice in most cases.

SysListPanelSet is already an extension of the SysListPanel class, and has one extra variable declaration – inSet variable of type SET. This is the entity that is going to store the values a user selects in the list panel. They can, when selected, be used for further processing.

The SysListPanelSet_TableBrowser class, used in the DEV_SysTableBrowser project (http://www.axaptapedia.com/DEV_SysTableBrowser) is an example, using this set to create the selected controls in the browser.

You should also notice from the SysListPanel hierarchy tree, that there are a lot of classes already available in the application, so it is wise to re-use one of the existing classes, if it matches your requirements or extend from one of them and not from the base class.

Again, the SysListPanelSet_TableBrowser class is an example, as it is extending from the SysListPanelSet_Fields class. It uses the functionality of this class to get the data about table fields, extending them with information about display methods and interaction with the browser form.

Creating a list panel – what methods need to be implemented?

Let’s say the SysListPanelSet_TableBrowser class does not exist yet, and we are just planning to create it, along with the form.

Creating the form is the easy part. There are not many requirements that have to be fulfilled here.

First of all, of course, you need to have a variable to reference your listPanel class. Put it in the classDeclaration of the form, so that it is visible in all form methods. And after that all that is left to do is to create an object of your listPanel class, and the class will do the rest of the work.

Here is what needs to be done:
  1. In the init() method of the form, you need to initialize the listPanel class, specifying, that it is this form you want the list panel to be on, the group that the list panel is going to be in on the form, and any other relevant parameters (for example, when using SysListPanelSet, you usually pass the current state of the values (inSet) as well.
  2. Most convenient way to accomplish this is by creating a static method with the needed list of parameters, and call this method from the init() method of the form. Usually, this method is named newForm.
  3. The SysListPanel class contains a lot of parm* methods, that you can use to modify the behavior of the list panel. The SysListPanelSet adds another method to that list, allowing to set the current set of selected values (parmInSet). You can see how these methods are used in Classes\SysListPanelSet_Fields_TableBrowser\newForm() method.
  4. After basic initialization you have to call the build method. The build method of SysListPanel class is responsible for actually adding all the needed controls to the specified form. Depending on the parameters that you set before calling this method, the list panel will/won’t add the “Add All”/”Remove All” buttons, the “Up” and “Down” buttons, will set the needed number of columns shown in the panels, etc. You can override any of the methods, adding additional functionality (see \Classes\SysListPanelSet_TableBrowser \build() method) or even completely rewrite the code of the basic method (this is not recommended, of course). Notice, that the build method should be called BEFORE super() in the form’s init() method, because FormBuild*Control classes are used to add controls to the form.
  5. After build method is executed, all FormBuild*Controls are initialized. You need to call the init method then, so that all Form*Control variables are initialized. This method should be called AFTER the super() call in the form init method, as Form*Controls don’t exist until super() is called.
  6. The last thing you have to do is call the fill method of your new class, so that the list panel is filled with needed data. Let’s talk about this method in a little more detail below.

The Classes\SysListPanel\fill() method, basically, consists of 4 parts:

  1. getData method is called. This is the method that gathers the data for the left and right part of the list panel. This is an abstract method, and it has to be implemented in the extending class. It returns a container with all the information for the list panel. It is different from class to class and depends on the data being shown in the list panel.
  2. Both parts of the list panel are cleared and list panel columns are created (the first time).
  3. fillView method is called for both parts of the list panel. These methods use the data generated in step 1.
  4. Buttons are enabled depending on the data in both list panel parts. For example, if there are no items selected (left part of the list panel), than the "Remove" and "RemoveAll" buttons are disabled.

The rest of the methods on SysListPanel class are for handling events that occur from user interaction.

The class is the handler of these events in most cases, controlMethodOverloadObject method is used to specify that when the list panel is built.

I guess, the only two methods left that are worth mentioning are the abstract methods addData and removeData. Both of these have to be implemented in the child class, providing the logic for adding and removing items from the left part of the list panel. For example, for SysListPanelSet class the implementation is very simple, just adding or removing the item from the inSet object. For classes extending directly from SysListPanel these methods are where the main logic is located, adding or removing records from the database. In most cases, these methods simply call a server method that does all the needed actions (Remember the rule of thumb – place database logic as close to the database layer as possible).

That is pretty much all you need to know to use and create list panels in Dynamics AX.

Conclusion

Of course, this is not a full description, and much can be added to the information posted here.

If you have any additions, corrections or questions, feel free to post them as comments.

See also

\Forms\Tutorial_SysListPanel

Friday, September 14, 2007

DEV_SysTableBrowser version 2.0 is out!

I have been asked by a number of my blog readers to move this tool to Dynamics AX 3.0, so here is the updated version of this tool. Now it works on both DAX 3.0 and 4.0 (tested on 3.0 SP5 KR2 and 4.0 SP1 and SP2).

Also, I added a couple of things I considered useful to this new release:
- The user field select dialog option has now, by default, all the non-system fields selected, so that users don’t get surprised when no fields are selected. I agree – it does look strange :)
- Now it’s possible to select display methods along with table fields in the user field select dialog. This feature was already working with FieldGroups, so I decided it could be a nice add-on to the User Field List option
- I also fixed a couple of old (and new, brought to us by 4.0 SP2) bugs that existed in the tool
- After reading some of the last posts on AxForum, I decided to add the ability of browsing temporary tables into my project as well, so that others may use them if they want :) (this will also include browsing temp tables data shown in forms from Tabax when the next version comes out)
- Now you can also use the browser for debugging purposes, launching it from code (this works for temp tables as well). Just write:

SysTableBrowser::browseTable(table.TableId, table);

where table is a cursor (second parameter can be omitted for non-temp tables). In this case the browser will open and code execution will stop until you close the browser (if not in a transaction). Third parameter controls if code execution should be stopped.

- There are two variables in method new of class SysTableBrowser
saveQueryRun = true; // Enables/Disables queryRun saving when new options are specified
savePosition = true; // Enables/Disables cursor position saving when new options are specified

The options allow to save the user filters and cursor position when changing setup options.
Both operations could result in performance problems on large tables.
If that happens (or you just don't need them), just turn them to false. :)

The download link is: DOWNLOAD

See extended installation instructions and tool description on: HOMEPAGE

What was a little disappointing is that a number of bugs I wrote about earlier were not fixed since SP1. Here are the 2 I mentioned before, again:
- UPDATE_RECORDSET command, when used in the table browser, crashes DAX.
- The left top edge position (the coordinates) of the table browser gets reset when any of the options are changed. I fixed this by specifying 0 instead of -1 for the leftMode and topMode properties of the design. So when you download this tool, the browser will stay in one place, which is nice ;)

Also, 1 new bug I found is for the Russian localization team.
- Changing the view (in the Unmodified version of the browser was causing the full table list to open, prompting the user for a selection of the table). This is caused by a small validation in the SysTableBrowser::main() method. SysSetupFormRun is supposed to be the classId of the calling object. And it is not, because some system wide changes were made to the SysSetupFormRun::construct() method. Anyway, I fixed this small bug as well.

OK. That’s all about the tool and the bugs. I have also been asked by a couple of my readers to write a tutorial on using the SysListPanel class.

That’s exactly what I am going to write about in my next blog entry. After all, there is a new class extending from the SysListPanel class in the DEV_SysTableBrowser project.

Monday, September 03, 2007

DEV_CreateNewProject tool version 2.0.0

Hello, everyone.

I finally got down to moving the latest version of this tool to Dynamics AX 4.0.
Now there is only one project for both versions (3.0 and 4.0)

If you haven't seen this project before, you are welcome to visit the homepage, which contains a description of the features, screenshots, installation instructions and more.

The download link with the new project is:
DEV_CreateNewProject version 2.0.0

Important:
The project was renamed to fit the naming conventions of Dynamics AX. The new name is DEV_CreateNewProject.

(If you want, you can remove the previous version (AxCreateNewProject)).
Leaving them in your application WILL NOT have unwanted effects on your system


Also, I would like to share some knowledge that came upon me today with you.
This might not seem strange to you, but it sure was a surprise for me.
While testing the new version in Dynamics AX 4.0 SP2, I noticed that the form size and position are not saved when I press OK in it.
I dug deeper into system classes and found one extra condition that was added before any data for the form is saved.

The extra condition is:
The AllowUserSetup property on form design must be Restricted or Yes.

So you should keep this in mind when developing forms in the future.

Well, have a great day, all of you.
And do try out the new DEV_CreateNewProject version.

Wednesday, August 22, 2007

tutorial_Form_Dynalink (a small tutorial on dynalinks)

Today I was asked the following question:

"In dynamics we have a Form Named "Form1" I created a button on it "Button1".
It will manage all the records related to the key in main form. There is dyna link created between the datasources. Only records of the currently selected main Key field will be shown. I need the selected KeyField value on the other form. How can I get it?"


So I wrote a small project to show the different possibilities.
In the project you will find 2 forms, 2 tables and a menuItem connecting the two forms.
3 ways of getting the current dynalink value are shown.

Here is a link to the xpo with the project:
download

Here is a screenshot of the result:



Forgot to give some explanations as well: :)
Basically, all the 3 form methods showing different ways of getting the dynalink value are called from the linkActive method in the second (slave) form.
This method is activated by the system every time a record in the parent form is changed, which allows for dynalinks to work. Great method :)

Monday, July 16, 2007

Fetching Data experiment (CacheLookup property)

Playing around with certain table properties at work, trying to improve performance, I decided to post some results today.

The original job was taken from the Dynamics AX Development training materials (III and IV), which, taking the opportunity, I would like to recommend for reading. Especially I enjoyed chapters dealing with performance issues (a topic that is very interesting to me :))

Well, they write about measuring caching there, which they, actually, shouldn't do, because the job they provided won't work in DAX 4.0 (the counters will be zero) (I guess it was simply copy-pasted from DAX 3.0 training materials - you should never use copy-paste, especially with code :) - trust me, been there many times)

Anyhow, I modified the job a little bit to make my research a little easier.
Here are the results I have received for SalesTable:


Basically, running the job may help you decide, what is the best CacheLookup property value for a given table. 
But first priority is reading about it in tutorials or the Inside Dynamics AX book (basically, it's almost the same information on this topic)

You can do some R&D yourself by downloading the job: download
Have fun!

Also visit the homepage

Wednesday, June 27, 2007

A bug in validation of methods' access modifiers and class abstract modifier

While testing the new feature of Tabax plugins today, discovered a bug in access modifiers validation.

It is performed only at compile time.
Which means, that if the compiler doesn't know what object the method belogns to, than the validation is skipped.
And you can run protected and private methods from whereever your code is executed.

Here is a simple example: (press cancel in the dialogs, otherwise you will get a RunTime error, because the method pack is not implemented in RunBase)

static void tutorial_AccessModifiersError(Args _args)
{
    Object runBaseObj;
    SysDictClass dictClass;
    ;
    runBaseObj = RunBase::makeObject(classNum(RunBase));
    runBaseObj.setInPrompt(true);
    runBaseObj.promptPrim();
    runBaseObj.setInPrompt(false);

    dictClass = new SysDictClass(classNum(RunBase));
    dictClass.callObject(methodStr(RunBase, promptPrim), dictClass.makeObject());
}

setInPrompt and promptPrim are both private methods. so they should not be allowed to be called this way.

The same thing can be achived by using DictClass.

The funny thing is:
while writing a test example for this post, I stumbled upon another bug - now it's about the abstract modifier of a class.

You all are probably aware that RunBase is an abstract class and cannot be initialized.
Well, in the example I showed this is done using 2 methods again :)

I guess someone should register these with Microsoft.

Tabax plugins' update - RecentWindows, RecentProjects

After developing 3 great tabax plugins I was feeling a little unsatisfied, because I wanted to add images to the popup menues.

AndyD has developed a class that allows me to do this now.

The project containing the class with the images is "shipped" separately. Depending on where you want to see images in your popups menues or not, you will be able to import it separately if you do.

Download:
You can use the following links to download the projects (version 0.1.1) and the MenuImages class.

RecentProjects v. 0.1.1 -download
RecentWindows v. 0.1.1 - download
Class MenuImages - download

Alternatively you can download them from their homepages on Axaptapedia.

RecentProject - homepage
RecentWindows - homepage

Screenshot: (RecentWindows)

Tuesday, June 26, 2007

AxPaint - make your DAX look cool :)

A couple of months ago I asked Alex Kotov from AxForum to modify a project he wrote for fun half a year ago or so. Today he sent me an e-mail with the project.

A short description of what the tool can do for you: :)
Basically, it just changes the backcolor of your DAX 3.0 (it does not work for DAX 4.0) installation.
You can choose a simple custom color you would like to use, or select an image from your hard drive to use as the background image.
you can select a couple of settings as well (ALL the settings are accessed by pressing Alt + S in DAX after launching the AxPaint form) - like stretching the image or using a 'transparent' background, showing your desktop (you have to set the image path to a specific location for that).

Nothing much, you'd say. But it sure is fun to work in DAX when a nice picture is seen in the background. :)

Installation instructions:

  1. Unzip the archived files.
  2. Place the .bat and .ocx files somewhere where you won't delete them accidently.
  3. Run the .bat file, which will register the .ocx
  4. Import the project into Dynamics AX - the project contains one form AxPaint.
  5. Run the form. It will automatically hide from view. Press Alt + S to run setup.
Custom settings (my preference):
  1. The image path is setup to C:\Documents and Settings\%username%\Local Settings\Application Data\Microsoft\Wallpaper1.bmp - this is the path to the current wallpaper in Win XP (without active desktop)
  2. Show desktop (like Delphi) option is set in the setup dialog.
  3. In the startupPost method of the Info class the following lines are added:  
  4. An external application is used to change the wallpaper on system startup. So every day I have a different look in my DAX :)
Project archive download link:
download

Custom code for the info.startupPost method:


 if (curUserId() == 'ikash')
    TreeNode::findNode("Forms\\AxPaint").AOTrun();


Link to the external WallChanger application:

download

Screenshots:

Monday, June 25, 2007

3 Dialog extensions

Performing one of the modifications on the project I am currently working on, I had to modify the behavior of one of the basic classes using the RunBase framework.

Anyway, what I needed to do was:

  1. Override the basic lookup for a specific control on the dialog.
  2. Prevent user interaction with other forms until the dialog is closed.
  3. Make some of the controls in the dialog mandatory.
Well, the perfect solution here would be to create a Form, and use it as the dialog.
But the code was very highly customized, so it would be a hard job.
So I decided to go another way, using what I have on hand, and that is the Dialog class.
For that, I needed a couple of modifications to the Dialog class, as it does not allow any of the 3 features I neded.

But what any developer should clearly understand when using dialogs is - this is just another form. Simple as that - Dialog is just another AOT form. What this means is that with a dialog we can do all the things we can do with a form.
Also, which is very nice and I thank DAX Developers for that, RunBase framework uses DialogRunBase class for showing forms, and this class is extending from class Dialog, so changes made to Dialog will also be available in RunBase framework.

Here is a small explanation of what has been modified:
  • Added a class Dialog variable showModal, which controls the modal state of the used dialog. 
  • Added a parm method to set the value of the showModal variable. So, basically, to make a modal dialog you simply have to call this method passing true as the parameter.
  • Added a method SetFormModal, which actually does all the enabling/disabling of windows (DAX 3.0 only, as DAX 4.0 already has built-in modal forms)
  • Modified runOnClient() method to allow server dialogs to run modal as well
  • Modified wait() method, which calls SetFormModal method (DAX 3.0 only)
  • AddField and AddFieldd modified to allow specifying a specific name for a control.
  • DialogField class was modified to allow setting the mandatory property (mandatory(), unpack() methods) and specifying a specific name for a control (new and fieldname methods)
The project contains 4 objects:
  • Class\Dialog - only modified methods
  • Class\DialogField - only modified methods
  • Class\Tutorial_RunBaseForm
  • Jobs\tutorial_DialogModalMandatory
The tutorials show the features added to the Dialog and DialogField classes (one of them is present in the basic application and is extending from RunBase, using an AOT form, the second is a job, showing the use of Dialog class)

DAX 3.0 Download link (was created in DAX 3.0 SP5 KR2) - DOWNLOAD
DAX 4.0 Download link (was created in DAX 4.0 SP1 EE) - DOWNLOAD

Important:
After importing the project do not forget to compile forward the Dialog class and to restart the DAX client.

Certain Issues you should know about:
  1. InfoActions, if present, will allow to access forms, if the infolog window with them was opened before the modal dialog was called.
  2. Mandatory property starts working only after a value is entered into the control. What this means is that if you simply press OK right after the dialog is opened, you won't receive an error (regular forms works this way too)
Credits
The modification allowing to specify a specific name for a DialogField was originally posted on the Russian Axapta forum

Tuesday, May 15, 2007

(DAX 3.0) SysExportDialog form extension

After working for some time with DAX 4.0 you can't help but notice the names given to exported xpo files - all the objects all prefixed with the type of the exported object.
I found this to be very convenient, that's why I wanted to lay my hands on the SysExportDialog form and add this feature in there as well.
And that's exactly what I did today.

This turned out to be a task a little harder than I'd hoped, because there are special methods on the TreeNode class that allow to see the type of the object. Those methods are not present in DAX 3.0 yet, so I had to write something similar (probably on a more primitive way, as this is the only place the code will be used - unlike the DAX 40 modifications which are now available everywhere the Treenode Class is used)

Also, I "fixed" a small issue that was present in DAX 4.0 with this: exporting an entire node of objects (e.g, Forms) resulted in the following name of the file : "_Forms.xp".

Anyway, here is the xpo file -- notice the neat name of the file ;). -- download Form_SysExportDialog.xpo
The file contains the SysExportDialog form only.
The original form was taken from DAX 3.0 SP5 KR2.

Hope you like it as much as I do ;)

Monday, May 14, 2007

3 great Tabax Plugins

As you might already know, starting with version 0.3 of Tabax, plug-ins are allowed to subscribe to events fired by the Tabax form. This fact couldn’t be left unnoticed. J So here are 3 plugins that you might consider useful for your DAX installations.

Before installing any of the plugins, you need to install Tabax 0.3 or later and the DEV_TabaxSDK
Use the following link to download the latest version of Tabax and SDK: http://axaptapedia.com/Tabax

DEV_TabaxPlugin_OpenInAOTdownload
(homepage - http://www.axaptapedia.com/DEV_TabaxPlugin_OpenInAOT)

This is a very simple plugin, based on a tool I made a while ago (you can download the original EditorScript at http://www.axaptapedia.com/Editor_scripts_OpenInAOT).
This tool is available only to developers (SysDevelopment security key).

Installation instructions are very simple: just import the project and refresh the AOD (this is specifically needed for the rich AX4 client)
Now you can open AOT objects just by typing their name in the Tabax form edit box (prefixed with ‘go’).
Here are a couple of examples:

  • “go InventTable” will open the Tables\InventTable node.
  • “go InventDimDevelop” will open the Macros\InventDimDevelop, etc.

DEV_TabaxPlugin_RecentProjects - download

(homepage - http://www.axaptapedia.com/DEV_TabaxPlugin_RecentProjects)


This plugin, when started (which happens automatically on startup of Tabax), adds a button on the Tabax toolbar. (it resembles an ‘Undo’ button).

This plugin keeps track of projects you use during the day, providing for a simple and fast way to open one of them.

This tool is available to developers only. If you do not have developer rights, the button will not be added to the toolbar.

Here is a list of what will happed when the button on the toolbar is pressed:

  1. A context menu is rolled down showing the list of projects recently used. (maximum 15 projects are shown, but the number can be changed in the plugin ClassDeclaration method)
  2. The first 10 entries are assigned hotkeys (1 to 10 (0) respectively).
  3. If Ctrl key is pressed, the last closed project is opened (the selection form is skipped).
  4. If Shift key is pressed, the selection form is opened, providing more functionality than the context menu.
  5. In the context menu of the selection form you can find menu Items that clear the contents of the recent projects list or control startup project settings.
  6. You can cancel the form by pressing Esc or the CloseDialog button in the top right corner

To users using Sidax this button will be very familiar, as it mostly copies the functionality available on the RecentProjects tab there.



DEV_TabaxPlugin_RecentWindows - download

(homepage - http://www.axaptapedia.com/DEV_TabaxPlugin_RecentWindows)


This plugin, when started (which happens automatically on startup of Tabax), adds a button on the Tabax toolbar. (it resembles a green ‘Recycle Bin’).

This plugin keeps track of windows you use during the day, providing for a simple and fast way to open one of them again.

This includes editor windows, AOT object windows and regular Axapta forms (this does not include forms opened from other forms).

This tool is available to both dev and non-developers. If you do not have developer rights, the AOT and editor windows are not kept track of and the recent windows list is used solely for DAX forms.

The nice part of this is the specific record you last used is remembered as well, so you can reopen a form and start working with the record right away. (AxPath is used for this)

The functionality of the toolbar button is similar to DEV_TabaxPlugin_RecentProjects.

That's it. Come back for more :)

Monday, May 07, 2007

Now I am a MCBMSS in Dynamics AX

More than 2 years have passed since the day I took my last certification exam.

Today I passed the AX 40-508 (DAX 4.0 Development Introduction) exam, so now I am a Microsoft Certified Business Management Solutions Specialist in Dynamics AX.

Don't you love it how certification titles get longer and longer every time their name is changed? :)

As for the exam itself, I should say that it was a little bit of a disappointment. At least, I was expecting more from it. Basically, it was the same DAX 3.0 Development Exam, with only 5 or so questions added for Dynamics AX 4.0. Of course, it's a DEV INTRODUCTION exam, so I guess I shouldn't be expecting much from it.

Anyway, I will be anxiously waiting for the MorphX Solution Developer Exam. Hope they will actually try to write some new questions for this one. ;)

Wednesday, April 25, 2007

My blog is now a Dynamics AX Related Community

As of today, my blog is present on the page of Microsoft Dynamics Related Communities.
You can see the list of related communities if you follow this link

Dynamics AX Tutorials - Tutorial 2 - Classes\Box

Here is a small project demonstrating capabilities of the class BOX in Dynamics AX.
Specifically, the following is covered in this tutorial:

  1. A short description of the system class BOX
  2. Creating a form from a class (using classFactory), launching different form methods, waiting for the form to be closed by the user and returning the selection
  3. Differences in implementation between DAX 3.0 and DAX 4.0

You can download the project from the following link:

  • download (for Dynamics AX 3.0 - only user layer)
  • download (for Dynamics AX 4.0 - only user layer)

Classes\Box is a simple class used throughout the DAX application. It provides an interface for showing a standard dialog with a number of selection options and a short message. This is very useful, especially during development, because it provides a fast way to show some kind of text information to the user.

The class contains a number of methods that can be extended with new ones (as shown below). All the methods are static and have the keyword client in the declaration, which forces the code in them to be executed on the client side.

The most commonly used methods of this class are:

  • box::info("message"); (for debugging purposes),
  • box::warning("message"); (for showing a warning message that the user won't miss)
  • box::yesNo("Message", dialogButton::Yes"). (for allowing the user to select the course of action for the underlying business logic)

All the methods mentioned above are simply creating an object of class DialogBox, which is system and doesn't allow to see its implementation. This class is therefore not covered in this tutorial.

----------------------

The rest of the methods is rarely found in the application code, and is suited for specific situations where you need to provide the user with the option of choosing from more options. (for example, when imporing a project, you see a dialog created by the method box::yesAllNoAllCancel();

The implementation of these methods is very much alike: (example mentioned above)

client static DialogButton yesAllNoAllCancel(str _text, //message
DialogButton _defaultButton, //default dialog button
str _title = "@SYS11132") //dialogTitle
{
Form form;
Args args;
Object formRun;
;
args = new Args();
args.name(formStr(SysBoxForm)); //form SysBoxForm is used to show the message
formRun = classFactory.formRunClass(args); //creating a FormRun object
formRun.init(); //calling init of the form
formRun.setTitle(_title); //setting title of the form (caption)
formRun.setText(_text); //setting message
formRun.setType(DialogBoxType::YESTOALLNOTOALLBOX); //setting the type of the form
formRun.setDefaultButton(_defaultButton); //setting the default button
formRun.run(); //calling run of the form
formRun.wait(); //waiting for user action
return formRun.dialogButton(); //returing the user selection
}

The example creates 2 objects that are needed to run a form from code:
Args args - not discusses here (used to specify the name of the form that is being created)
Object formRun - that is the actual object of the form being created.

You might have noticed that it is of type Object and not FormRun. (using the base type)
This is done on purpose, as there is no compile-time validationg of methods actually existing on the form. If the method doesn't exist, you will receive a runtime error, which is not really appropriate in a live environment. So in your code you should chech that the methods being called do actullay exist. (Global method formHasMethod can be used for this purpose)

After the form is initialized and all the setMethods() are called, the Run() method is called. This method executes the form and shows it on the screen.
After the Run Method we see a call to formRun.wait(); This method notifies the RunTime that the code execution should stop here and wait until the form is closed. (if this method is used on a form to call a child form, the parent form cannot be closed before the child form)
[Note: The alternative method here is the detach method (behavior of MenuItem calls)]

After the user closes the form, the dialogButton method on the form is called to return the selected value. [Note: Notice, that the methods on the form are still accessible, even though the form is already closed by the user. This happens because the formRun object is not yet destroyed]

-----------------
I added another method to the box class - yesNoWaitForm. It opens a form that looks kinda cooler than the standard forms, because it has the option of autoclosing after a set period of time. Well, everyone can find his own uses for this form. The form name is Dev_SysBoxForm and it is an almost complete duplicate of the system SysBoxForm form. The only big difference is that this form is set modal, and that the text of the default button is appended with the remaining amount of time before the form is autoclosed. [Note: SetTimeOut method is used, which is not covered in this tutorial]

There were differences in implementation (compared to the sytem form SysBoxForm). The main are listed below:
  • DAX 4.0 already has a modal window option (wait(TRUE)); So custom methos are removed from the form
  • DAX 4.0 has the minimize and maximize system buttons visible on the dialog form, and they had to be turned of on the form design.
  • In DAX 4.0 The return value of method formRunObj.dialogButton() was not automatically converted to the correct type. So an extra variable way added to the method to convert the result to a specific type of DialogButton. [Note: I think that this is a bug]
  • The font size of the html (message) was increased by 1, because the default font size seems too small to read.

The project also includes a job that contains a couple of examples of using the new method. Enjoy!

Thursday, April 19, 2007

Two very useful projects for DAX

1. DEV_FormControlInfo
Today I downloaded a very nice project for DAX 4.0 from www.axaptapedia.com
It inserts a number of lines of code into the SysSetupFormRun class, method task, providing a hotkey to access usefull information about any control on a form.

The hotkey is 'Ctrl + Q'.
Here is a screenshot of the result:

I moved the project to DAX 3.0, because I liked it a lot. Previously I used the Tabax button, which is convenient too, but does not provide as much info as posted above.

Here is the download link for the project:

2. DEV_AxFind


Also, my friend AndyD created a very good project for DAX 4.0

Description: After moving to DAX 4.0 a lot of users complained about the 'Ctrl + F' key combination. Now, instead of a 'Filter by Field' operation it opens a 'Global Search' window, which is uneasy to use so far.

Anyway, AndyD created a small dll file that replaces the 'Ctrl + K' key combination with the 'Ctrl + F' key combination, leaving the 'Global Serach' intact, but, at the same time, providing a well known interface for DAX users.

Thanks again, AndyD. :)

All you have to do is download the dll file (donwload link) and add the following lines of code into the Info class:

2.1. Info\\classDeclaration
classDeclaration
{
.....
DLL dllAxFind;
}

2.2. Info\\startupPost
void startupPost()
{
InteropPermission perm = new InteropPermission(InteropKind::DllInterop);
;

// DEV_AxFindReplacement Replace Keys F and K when used with the Ctrl key 19.04.2007 IKASH -->
perm.assert();
dllAxFind = new dll(@"D:\Install\Dynamics AX\Dynamics AX 4.0 SP1 EE\axfind.dll");
CodeAccessPermission::revertAssert();
// DEV_AxFindReplacement Replace Keys F and K when used with the Ctrl key 19.04.2007 IKASH <--
}

Notice, that the path to the DLL file, specified above, will be different - insert the correct path to the DLL file instead.

Reboot the DAX client. And you are done.

Friday, April 13, 2007

Buy MorphX IT in Russian

Now you can buy the MorphX IT (by Steen Andreasen) book about Dynamics AX Development in Russian language as well.

Please visit http://www.lulu.com/content/723888 to order the book now (Paperback or download versions available)

Also, there is a special offer for people living in Kiev, Ukraine and Moscow, Russia.
You can contact

  • Ivan Kashperuk to order a paperback copy of the book to be delivered to Kiev.
  • Mihail Rzevsky to order a paperback copy of the book to be delived to Moscow.
This is a very good offer, as you will save a lot on delivery costs and book price. Also, you can get it signed by the translator on location FOR FREE! :)
Also, you should understand, that this is simply about helping people to buy the book, it is not a commersial affair, as translators won't get any or very low revenues from this.

P.S. lulu.com also provides a review of the book and a free sample chapter preview.
P.P.S. You might have to wait for the delivery for some time, as orders are processed only after a certian quantity is collected.

Saturday, April 07, 2007

Add-On: Extended SysTableBrowser

Hello, readers.
Today I provide you with another tool for Dynamics AX developers. It is a modified version of the SysTableBrowser (See picture 1).
picture 1


Important:
After importing the project refresh the AOD (Tools\Development Tools\Application Objects\Refresh AOD)

Modifications:

  1. The table browser does not change its position when a different setup is selected. (Unlike standard system behavior in DAX 4.0)

  2. The AutoReport option was extended, and now you are able to select any of the table field groups (See Credits).

  3. Another selection option was added, providing the means to select any of the table fields to be shown in the grid. To do this, just press the ‘Select Fields’ button and select the fields you want displayed (See picture 2).

  4. Added a list of presets for the SQL window. (SELECT, UPDATE, DELETE). The list can be easily extended to include other presets you often use.

  5. Extra logic was added to the ExecuteSQL button, which executes the SQL string that the user has put into the SQL window. If it is a simple select (for example, generated by the SELECT preset), the ds query is executed instead of the sql string. This will bring back the sorting and filtering options that disappear after using the sql string query.
  6. Added the ability to sort columns by name or by id. In some cases (when, for example, you cannot find a specific field) it really helps out! (See picture 3)

picture 2
picture 3


Possible future improvements:

  1. Add display methods of the selected table to the list of fields in the select dialog.

Credits:


The modification was inspired by a similar one performed by Nicolai Hillstrom for Dynamics AX 3.0. I moved it to DAX 4.0 and added some extra features I considered useful. One of them is implemented here (even thought I wasn’t able to download it and see how it is programmed).

Wednesday, March 28, 2007

My first attempts in Dynamics AX 4.0 SP1

Last week I started trying out what is Dynamics AX 4.0 SP1 European Version (Russian Localization included), creating a project for data import using ODBC connection (from an external SQL database).

In the process, I decided to take note of what I like in the new release, and also write down any bugs I find so that someone can send them over to Microsoft to be fixed.
(this is compared to Dynamics AX 3.0 SP3, but also tried out in Dynamics AX SP5 KR2)

Here is the small list I got so far:
New features:

  1. When pressing Enter to go to the next line in the X++ Code Editor window, the cursor is automatically positioned on the same column as the previous line. This was also present in DAX 3.0, but only after 2 lines are positioned in the same way (when adding a lot of conditions in the where clause, for example). But, there is a small 'bug' here. If you put the cursor at the end of a line of code, press Enter, the cursor will automatically get positioned under the line. Press Tab to indent one time. And then hit Enter again. The cursor is supposed to be directly under the line in the same column. But instead, it is position in the first column of the next line.
  2. When exporting any object to an .xpo file, the file gets a friendlier name, prefixed with the type of object that is being exported. For example, if you export the InventTable form, the file name would be 'Form_InventTable.xpo', which is pretty cool and helps to find the needed xpo file easier later.
  3. The Hot Keys for the Dynamics Debugger have been changed from F7, F8 to F10, F11. This is very inconvenient at first. And not just because you have to press different keys now. But because the F7 key actions were moved to F11, and F8 - to F10. By now I was used that the left key would take me deaper into the implementation. now it's vise versa.

And here is the bug list (some of them might have been fixed by now, or moved to the Known Issues, but I am unaware of this, sorry):

  1. The multiline comments are not colored correctly. The first slash is black, if the multiline comment spreads over more that one line. The rest of the comment is green, as it should be.
  2. In the table browser form, the UPDATE_RECORDSET command crashes Dynamics AX.
  3. After compiling a project, some of the tables in it are marked as DIRTY (red line near the name). This does not happen to all of the tables, but to those that it does, it happens all the time. Walkthrough: select a table in the AOT, compile it. (no changed done to the table). Then, compile the project. The previously selected table is marked in red. also, one of the tables in my project is always marked dirty after compilation.

That's all I have stumbled upon so far. And I am pretty sure more is to come. ;)

Friday, March 23, 2007

MorphX IT by Steen Andreasen in Russian is available for sale

The book on Dynamics AX development MorphX IT is finally out for sale.
So far there is only one location you can purchase it from (only paperback edition):

http://www.lulu.com/content/723888

I am still trying to find a Print on Demand service based in Moscow or Kiev, but no luck so far.

If you have any questions or suggestions regarding the book, feel free to e-mail me or post a comment here.

P.S.
Here is information on delivery costs (for Kiev, Ukraine):

economy - $10.81
standart - $17.50
express - $26.09

Friday, March 16, 2007

AxCreateNewProject version 1.3.2 released

Updated the project for creating projects ;) to version 1.3.2

Download link

Change log:

  • When a project is updated, or "duplicated", the project settings are not stored, so that the node selections and project name & prefix are as they were last time the project was actually created. Most of the developers have a fixed project prefix and name, and layout. But sometimes, rarely we have to modify the layout. Then, when we need to create another project, we have to reset the settings to the stardard layout we used. Well, now we do not have to do it outselves.
  • The "Copy Objects" button is always visible now, only disabled when not needed - this is done to promote the using of this feature, as I gather that most devs don't even know that it exists. :)
  • MenuItemButton text has been modified to show the behaviour when pressing Ctrl (updating a project)
  • Another project group node was added to the dialog - More... This group node contains the rest of the Data Dictionary Nodes. By default, it is collapsed, because rarely used. The rest of the AOT nodes (SystemDocumentation nodes) will not be included.

Also, the tutorial on MultiSelect options has been updated slightly, giving the opportunity to test Set(Types::Record) and InventTable.setTmp(). See homepage for details.

Tuesday, March 06, 2007

Dynamics AX Tutorials (continued)

Hello, readers.

After posting the first AX tutorial about Multiple Selection options in Dynamics AX we had a very interesting discussion about what's best to use in DAX at www.axForum.info
After this discussion, I decided to dig into the issue some more and see for myself, what is the best choice here.

So I modified the previous project a little bit: (you can download it here)

  • Added a Server-Based class that does all the processing of selected lines
  • Added a temporary table, tmpInventTable, consisting only of one field, ItemId.
  • Added a job - an approximate way to determine the memory wastes for filling different types of objects.
  • Added 2 tab pages to the form, so the form now allows five tipes of processing:
    • Using a Set
    • Using a Set (the query uses a JOIN)
    • Using a Temporary Table
    • Using a Temporary Table (the query uses a JOIN)
    • Using standard DAX way with multiselecting records

The good thing is that now everyone can try out the different options and choose what is most appropriate for his specific needs.

After this, I also did a test run on a 3-tier installation and on a 2-tier installation.

Here are the Memory test results: (the first is in 2-tier, the second - in 3-tier configuration)


Here are the Processing test results: (the first is in 2-tier, the second - in 3-tier configuration)

The results of my tests can also be found at the homepage of this tutorial.

As you can see from the results, the 3-tier environment provides more balanced results. And in 2-tier I got 25 to 60!!! times increase on Processing tests when not using joins. I would love to know what your resuls will be.

Filling in data is also slightly slower when using Temporary Tables, but the difference is not that great, especially if you take into consideration the amount of records inserted into it (up to 100 000)

You comments and suggestions are very welcome.

Monday, March 05, 2007

AxPromptDBSync - a simple project that allows to choose whether to synchronize the AOT with the database at the moment or not.

This should be used with extreme caution and only by experienced developers (people, who know what they are doing)

Get the tool at axaptapedia

Someone may ask - why would I need to prevent syncronization? Isn't it what should be done at all times?
And the answer is, of course, YES.

But just stop for a minute and remember the amount of time you have to wait till syncronization is over after adding just a single EDT or tablefield. Or, what most people do, Break the operation and (if you managed to actually break it) do it for every field being added. Or, which is even better, export the project, modify the xpo file and then import it back into DAX. :) A nice way, no doubt.

Well, here is a small and simple solution. When syncronization is about to begin, a dialog will popup asking if it should continue. If not, the syncronization will not be performed.
Actually, you can specify the exact way the system should behave through your user settings. The 2 checkboxes are added to the SysUserInfo table: one specifies if the syncronization should be performed, the second - if the user should be prompted with a dialog.

My settings are: 1 - not checked (means should go on with Sync), 2 - checked (means the prompt dialog is going to pop up)
This thing really saves a lot of time.

Wednesday, February 21, 2007

Dynamics AX Tutorials

Hello, everyone.

I was going through the Jobs node in my application recently, and stumbeled upon a lot of good examples of different programming technics. I thought it would be nice to share what I have :)

So with this post I will start a series of tutorials on Axapta development.

Today's post is about selecting multiple records on a form (using checkboxes instead of standard Axapta method)

The homepage for this tutorial in on Axaptapedia

It is a simple tutorial form based on InventTable datasource. You can select multiple lines and process the lines by pressing Process lines button.

Here is a short list of what is covered in the tutorial besides the main point of processing selected lines:

  1. Using edit methods in a grid of a form.
  2. Using Foundation class Set to collect selected lines.
  3. Using SetIterator class to go through elements of a Set object.

Preview of the form

Thursday, February 15, 2007

AxCopyTableFieldListToClipboard - another IDE extension tool for Microsoft Dynamics AX 3.0

Hello, readers.

Here is another tool for Dynamics AX developers.
Homepage

All it does is populates the Windows Clipboard with the lines that you can paste into your code, so you won't have to retype the same code many times.

Download the tool here

Features (You can ... ):

  1. Insert a variable declaration before using the name; You will have to move the declaration where it belongs if pasting in the middle of a method.
  2. Insert a call to clear() method of a table variable in order to clear its contents. This is useful, for example, when doing inserts in a loop.
  3. Specify a different variable name than the one by default (tableName). If the variable is unacceptable, the image on the right will point out the mistake.
  4. Choose which fields to copy into the clipboard. There are 2 presets so far. The list will be extended in future releases.
  5. Insert a call to insert() or update() after the lines with field values assignment.

The tool can be integrated into the system in a couple of ways:

  • Insert the menuItem AxCopyTableFieldListToClipboard into the SysContextMenu menu. The text "Copy Table FieldList" will be automatically added to the context menu on AOT objects. In order to sort this out and show the text only for tables, you have to modify the method verifyItem of the SysContextMenu class. Paste the following code into the appropriate section (after case MenuItemType::Action:)
    //--> AxCopyTableFieldListToClipboard_ikash date=2007-02-11 txt='Show in menu only for tables'
case menuItemActionStr(AxCopyTableFieldListToClipboard):
if (this.selectionCount() != 1 firstNode.AOTIsOld())
return 0;

if (!docNode && firstNode.sysNodeType() == 204)
return 1;

return 0;
//<-- AxCopyTableFieldListToClipboard_ikash
  • Insert the menu Item into the GlobalToolsMenu or the DevelopmentTools menu. Then select a table in the AOT and run the menu.
  • You can add the bmp image attached to the project into the plugs folder of Tabax and you will automatically be able to launch the tool from the Tabax toolbar.
  • You can select a table name in the editor and call the tool from the editor scripts. In order to insert the tool into the editor scripts create a method with the following code in the EditorScripts class.

void AOT_Copy_TableFieldList(Editor e)
{
Args args = new Args();
;

args.parmObject(e);

new MenuFunction(menuItemActionStr(AxCopyTableFieldListToClipboard), MenuItemType::Action).run(args);
}


Also (especially DAX 4.0 users), take a look at the link to Casper Kamal's post. He describes similar functionality already included in the 4.0 release.
Hey, great to know MS developers and I are thinking the same thoughts ;)
Anyway, here is the link:
http://casperkamal.spaces.live.com/Blog/cns!9138ED475277CD63!221.entry

Thanks to:

  • aidsua - for a hint on the match function
  • AndyD - ListView setColumnWidth help and WinApi stuff




Thursday, February 08, 2007

EditorScripts.addIns_OpenInAOT() script update

HOMEPAGE

Moreover, I updated the script that finds the selected object in the AOT with the new code fixed by AndyD - now the selected line is parsed correctly even if selected by keyboard.
You can download it from it's homepage only, as this editor is not well suited for copy/pasting of code. :)

AxCreateNewProject version 1.3.1 available

I have also upgraded the tool for creating new projects to version 1.3.1

The new feature are:
Version 1.3.1
Fixed a small bug I stumbled upon recently: If you temporarily turn off the project prefix that contains a long name, and enter a long name for the project, the validation fails telling that the project name is too long - the CheckBox value is not analyzed.

Version 1.3
Now you can update an existing project adding new project nodes to it. Just select the project you want to update and hold the Ctrl key when calling the AxCreateNewProject tool. This will automatically initialize the Settings Tree with the project group nodes found in the selected project. Also, the warning confirmation message won't be shown when you press the OK button and the existence of a project with the same name is not considered an error in the image window.

Moreover, you can now selectively duplicate the objects of an existing project together with the project group nodes. In order to do this select an existing project for update and simply input a new name for the project. You will notice that a button Copy Objects will appear in the bottom left corner of the dialog window. Pressing this button will add the objects found in the selected project into the Settings Tree and will be copied into the new project as well. You will be able to deselect some of the objects (see Known Issues) if you do not need to carry them over to the new project.

You can download the new version HERE or from the Homepage

AxGoToDeclaration


I haven't posted in a while. Work, work...

Well, meanwhile, I made some new handy tool for Axapta developers.

Purpose
Finds the declaration of the selected variable and opens the editor on the line with the declaration

Functional capabilities
Searches the current method first. If the declaration is not found, goes to the root of the object and looks in the classDeclaration method. If still not found, continues on with the parent of the class.

Implementation
In order to use the tool simply import the project
HERE
and post the following code as a new method of the EditorScripts class:

void AOT_goToDeclaration(Editor e)
{
AxGoToDeclaration goToDeclEngine;
;
goToDeclEngine = new AxGoToDeclaration(e);
goToDeclEngine.goToDeclaration();
}




Known Issues:
  • ParserClass does not parse the constructor (new) method. So variable declarations cannot be found from this method.
  • Does not find variables this, element, etc.
  • Does not find objects with AutoDeclaration set to Yes on forms, nor the datasources

What is planned for upgrade:
  1. Open AOT objects when this or element is selected (table, class, form, etc)
  2. Open AOT objects with the property sheet for objects with AutoDeclaration = Yes
  3. Include global classes into the search

Credits

Thanks to

  • AndyD - for the timer AOT edit code and the selectedLine method modifications
  • MaxBelugin - for ParserClass description

Feedback

If you have any comments or suggestions, please feel free to contact me.

Wednesday, December 20, 2006

AxCreateNewProject tool Version 1.2

I made some additions and modifications to the AxCreateNewProject tool.
The link to the orignal post about the tool:
AxCreateNewProject Version 1.1.

Modifications are descriped on the homepage:
AxCreateNewProject HomePage

Friday, December 08, 2006

A little modification / add-on to Sidax:

I use one of the features of Sidax most of all - it's the recent projects tab. (we have a lot of projects and I have to work with a lot of them at the same time). So performance of this tab is most critical to me.

And what was wrong is that from time to time I would stumble onto project names that didn't exist anymore, but still were up high in the list of recent projects.
So what this modification does is just verify that the project exists before showing it in the list of recent projects.
(this verification is performed only when the recent projects tab is opened, so it won't cause any performance issues)

To add this modification into your sidax installation, you have to do the following:
1. Add a method to Forms\Sidax:

void updateMruProjects()
{
int i;
TreeNode privateProjectTreeNode;
TreeNode sharedProjectTreeNode;
TreeNodeName projectName;

boolean existsProject(TreeNodeName _projectName)
{
TreeNode project;
;
project = privateProjectTreeNode.AOTfindChild(_projectName);
if (project)
return true;
project = sharedProjectTreeNode.AOTfindChild(_projectName);
if (project)
return true;
return false;
}
;
privateProjectTreeNode = SysTreeNode::getPrivateProject();
sharedProjectTreeNode = SysTreeNode::getSharedProject();

for(i = 1; i <= conLen(MruProjects); i++)
{
projectName = conPeek(mruProjects, i);
if (!existsProject(projectName))
{
if (element.openedProjects().exists(projectName))
element.openedProjects().remove(projectName);
MRUProjects = conDel(MRUProjects, conFind(MRUProjects, projectName), 1);
}
}
this.updateHistory();
}


2. Modify an existing method Forms\Sidax\toglleBut, adding 2 lines at the end:
    if (activeTab.id() == historyTab.id() && !collapsed)
element.updateMruProjects();


That's it. Now the next time you open the recent projects tab, the unexistent project won't be shown. Enjoy!

Tuesday, December 05, 2006

Adding Menu References

Many developers often find it very confusing when trying to add a menu reference into an existing menu.
The reference just doesn't want to be added. :)
And what confuses even more is that some of the menus are added normally, while others are not!

Let's look at an example:
"After creating of a new menu - menu1, I want to add 2 existing menus into it as references: Cust and Vend.
I right-click the menu1 node and select add->menu reference. Drag over the Cust menu (and everything goes fine), and then I try to drag over the Vend menu - and it DOESN'T work! I am lost. what can be the reason for this?"

The explanation is simple:
The menus that were expanded since the time you launched the client, can't be added as references.
You can experiment with this: Try opening the AX client and dragging over a menu as a menu reference. You can see that it works. Now, expand the menu in the AOT and try adding it as a menu reference again. You can see that it is impossible to add it any more. So, to avoid having problems when adding a menu as a reference, you should re-enter the Axapta client and, before expanding the menu, add the needed menu as a reference.

Original article:
http://erpkb.com/Axapta/OshibkaSozdanijaSsylkiNaMenju

Friday, November 24, 2006

Description of ClassBuild class:

Today I want to write about using the class ClassBuild.
A collegue of mine recently used this class for extending Axapta's IDE, so I decided you all should know about this class too.

OK, let's start with the declaration of the class:
It's simple, the class isn't extending any other class, a variable of type class ClassNode is declared together with a macro #aot - it contains pathes to all the objects in the AOT

X++:
public class ClassBuild
{
ClassNode classNode;
#aot
}


The class contains the following methods:
  • void new(str _name, boolean _allowExisting = true) - this is the constructor of the class

  • void addMemberVariable(str _variableType, str _variableName) - this method is used to create a variable declaration in a class

  • TreeNode addMethod(str _name, str _source) - this method is used to create new methods and set their source code

  • void addSourceToMethod(str _memberFunction, str _addSource) - using this method we can set the source code of an existing method

  • ClassNode classNode() - this method returns a ClassNode object pointing to the created class

  • public MemberFunction getMethodImplementation(str _methodName, boolean _includeParents) - the method return a MemberFunction object, which has methods to edit or view the source code of the specified method of the class

  • public str name() - the method returns the name of the created class

  • TreeNode overrideMethod(str _name, str _newSource = '') - this method is used to override the method of the parent class in case one exists


  • I will explain how the class should be used on a specific example: (click the image to enlarge)


    Explanation:
    In line 6 we create a new Object of class ClassBuild. Into the constructor we pass the name of the class we want to create and an optional paramter, which controls the execution of code in case the class already exists in the AOT.
    After the execution of this line the class already exists.
    After that we add a method test() to our class and set the source code for this method.
    Then we add a member variable of our class, and will try using this variable in a second method we create - test2(). You can see that here I did this in 2 steps on purpose - to show the way you can use the method addSourceToMethod().
    OK, now all the methods are created and we have to compile our class. For this we can use the method AotCompile() of class TreeNode, which we access through the method classNode of the created class.
    Now, to see how 2 other methods work, we show a message dialog with the name of the class being created and the source code of one of the methods.

    Then, just to show you the class works and is ready to be used, we can call one of its methods for execution.
    For this, we use the class DictClass and its methods, but I will not discuss it in this post.

    That's it. Try running the attached job and see how it works!
    Attachment: Job17.xpo


    There is also another way of creating the same class - by using the UtilElements table: (code provided by AndyD from AxForum)

    UtilIdElements utilIdElements;
    TreeNode tn;
    ;
    utilIdElements.initValue();
    utilIdElements.Name = "newClass";
    utilIdElements.recordType = UtilElementType::Class;
    utilIdElements.insert();
    tn = xUtilIdElements::getNode(utilIdElements);
    tn.AOTcompile(1);
    tn.AOTsave();



    See also: Classes\FormBuild, Classes\DictClass

    Adding an AND condition in a queryRange


    Wamr from AxForum found an interesing feature of fieldId2Ext global method:


    X++:

        Query       q = new Query();
    QueryBuildDataSource qbds;
    ;

    qbds = q.addDataSource(tableNum(InventTable));

    qbds.addRange(fieldNum(InventTable, ItemId)).value("8");
    qbds.addRange(fieldid2ext(fieldNum(InventTable, ItemId),1)).value("2");

    info(qbDS.toString());
     
    But you have to use it with caution, because you won't be able to find this range afterwards. 
    so, searching for
    qbr = qbds.findRange(fieldId2Ext((fieldNum(InventTable, ItemId), 1));
    won't return you the range with the value "2", but the one with the value "8"
     
    You can find the range, specifying the exact occurrence of it in the query:
     
    qbr = qbds.findRange(fieldNum(InventTable, ItemId), 2);

    Monday, November 20, 2006

    AxCreateNewProject
    Homepage

    AxCreateNewProject is a nice tool to help you get started on a project - it will create a shared or a private project with specified project nodes for you and open it in a new window, so that you can start edding objects right away.

    Also included in the zip file: a bmp image to add this tool as a plugin for Tabax


    And after you press OK a project will be created: (see an example below)

    Monday, November 13, 2006

    Sidax - a sidebar tool for DAX 3.0

    Max Belugin (AxCoder) has made some upgrades to his tool - sidebar for Axapta - Sidax.
    Current version is 0.3.7 beta14
    The link to download this great tool is:
    http://erpkb.com/Axapta/Sidax/files?get=sidax0.3.7beta14.zip

    Enjoy!

    Wednesday, November 08, 2006

    Hello, everyone.
    This blog will mostly be about Dynamics AX (formerly Axapta).
    (This is what I do for living and what I am interested in)
    Also, here is a link to another resource of mine, where I am planning to store different projects and thoughts I consider interesting:
    http://infostore.org/user/kashperuk/DynamicsAX

    I want to start off with a small post about Axapta Label System.

    I am translating a book on Axapta (MorphX IT, Steen Andreasen) into Russian language. I will tell about it in more detail in a little while, when the traslation is finished and proof-read.
    So, while doing the translation of an Appendix chapter, I stumbled on something I have never read about in the past.

    It's about searching labels in Axapta:
    "When searching for a label using <> will narrow your search. If you want to look up the label 'Customer', it will perform faster by keying in <Customer> as only labels with the exact text 'Customer' will be found. To find all labels starting with 'Customer', you simply enter <Customer."


    Also, as Max Belugin pointed out to me, regular expressions are used in the search.
    You can read about different Regular expressions by opening the AOT node:
    \System Documentation\Functions\match