Friday, 17 October 2014

Progress bar in some(lengthy) operation

Progress bar in some(lengthy) operation


SysOperationProgress is a class to use operation progress indicator

static void SysOperationProgress_PrimeNumber(Args _args)
{
#avifiles
boolean checkPrime,_showProgess = true;
SysOperationProgress progressBar = new SysOperationProgress();
int counter,out;
;
counter = 1;
out = 1000;
while(counter < out)
{
checkPrime = ((counter mod 2)!=0 && (counter mod 3) !=0);

if(checkPrime)
{
info(strfmt("its a prime number %1",counter));
}
progressBar.setCaption(strfmt("Generating the prime number for %1",counter));
progressBar.setAnimation(#aviUpdate);//#AviFindFile);//progress.setAnimation(#AviTransfer);
progressBar.setText(strfmt("Processing %1 out of %2",counter,out));
counter++;
}
}

Args Class

Args class



The Args system class is one of the most widely used classes in Axapta. Args is an abbreviation for arguments and an Args object is used to pass information from one object (caller) to another newly created object.
Using Args for object creation
Args    args = new Args("CustTable");
 FormRun formRun = ClassFactory.formRunClass(args);
 ; 
 formRun.init();
 formRun.run();
 formRun.wait();
caller:
public Object caller( [Object _value] )

this method gets or sets the calling object. When creating an args object directly through code, the caller will not be automatically set, so you should set it yourself.
Record:
public Common record( [Common _value] )

this method gets or sets a table buffer (record) attached to the Args. A buffer of any table can be attached to an Args object using this method. Be aware when retrieving the buffer that there will be no compile-time check of table id. You should use the dataset method below to check the contents of the buffer.
If the caller and callee are on different tiers, then the applications will automatically copy the buffer to the target tier.
Dataset:

public tableId dataset()

this method gets the table Id of a table buffer (record) attached to the Args.
To safely retrieve an attached record from an Args object, use code similar to that shown below. This checks to ensure that there is an attached record, and that it is in fact a SalesTable record, before trying to assign it to the salesTable variable.

if (args.record() && args.dataset() == tableNum(SalesTable))
  salesTable = args.record();
parm:

public str parm( [str _value] )
parm is used to pass a string variable to the called object

parmEnum:
public anytype parmEnum( [int _value] )
see parmEnumType

parmEnumType:
public int parmEnumType( [int _value] )
parmEnum and parmEnumType are used together to pass a Base Enum value through to the called object. An example is shown below.
args.parmEnumType(EnumNum(AddressType));
args.parmEnum(AddressType::Delivery);

parmObject:
public Object parmObject( [Object _value] )
parmObject is used to pass a reference to any object to the called object. Be aware of client-server issues if the caller and callee are on different tiers.

menuItemName:
public final str menuItemName( [str _value] )

menuItemType:
public final MenuItemType menuItemType( [MenuItemType _value] )

A short tutorial on how to open a form in Dynamics Ax (Axapta) by code.

Just take a line of code:

new MenuFunction(MenuItemDisplayStr(CustTable),MenuItemType::Display).run();

The above code will open the CustTable form. That's all it takes.

Now if you want to supply some arguments to the opening form, this is also possible with the optional args parameter.

static void FormOpen()
{
Args args = new Args();
;
args.record(CustTable::find('CUS-001'));
new MenuFunction(MenuItemDisplayStr(CustTable),MenuItemType::Display).run(Args);
}

This code will open the CustTable form and filter out the customer with accountnumber CUS-001.

RunBase framework

RunBase framework:


The RunBaseBatch class extends the RunBase class and allows one to create classes (jobs) that can be added to the batch queue. Once the job has been added to the queue, it will be executed by the batch server. This concept is known as batch processing.

Whenever you write a class that typically asks a user for input and then starts a process based on that input you use the RunBase framework as most of the typical methods needed for such a Job is already implemented in the RunBase class. This means that using the RunBase framework is done by extending RunBase either by directly extending RunBase or by extending a class that extends RunBase.

For more: RunBase

Some of the features implemented in the RunBase framework are the following:

• Run: The main flow of the operation

• Dialog: Prompting the user for input and storing that input

• Batch execution: Schedule the Job for later execution

• Query: Used to select data

• Progress bar: Shows the progress of a task

• Pack/unpack with versioning: Remember variable values until the next time

the task is executed              

Pack and Unpack method:This method is a standard method inherited from RunBase. It is used to save
the values that the user selects and store them until the next time the user executes
the class.
public container pack()
{
    ;
    return [#CurrentVersion,#CurrentList];// + [super()];
}
And under unpack:

public boolean unpack(container packedClass)
{
    container       _base;
    boolean         _ret;
    Integer         _version    = conpeek(packedClass,1);
    switch (_version)
    {
        case #CurrentVersion:
            [_version, #CurrentList, _base] = packedClass;
            //_ret = super(_base);
            break;
        default:
            _ret = false;
    }
    return _ret;
}
And your class declaration looks like:

class ItemCreationApprove extends runbase
{
    Dialogfield fieldapprover;
    approvedby  approver;
    #define.CurrentVersion(2)
    #localmacro.CurrentList
        approver
    #endmacro
}
Other framework in Microsoft dynamics AX:

Ø  Runbase Framework

Ø  Batch Framework

Ø  Dialog Framework

Ø  Operation Progress Framework 

Ø  NumberSequence Framework

Ø  SysLastValue Framework

Ø  AIF-Application Integration Framework

Ø  Wizard Framework

Ø  Infolog Framework

Ø  Unit Test Framework

=============================================================

Demo : Use Query created in AOT and update a table using batch
class SalesFactoringBatch extends RunBaseBatch
{
    SysQueryRun                    queryRun;
    DialogRunbase               dialog;

    #DEFINE.CurrentVersion(1)
}

[
SysEntryPointAttribute(true)
]
public void run()
{
    CustTrans       custTrans; 
    if (! this.validate())
        throw error("");

    while (queryRun.next())
    {
        custTrans   = queryRun.get(tableNum(custTrans));
        ttsBegin;
        custTrans.selectForUpdate(true);
        custTrans.CustFactored = NoYes::Yes;
        custTrans.update();
        ttsCommit;
    }
}

protected Object dialog()
{
     dialog          =  super();
//Shows query in Dialog,( new DialogRunbase("@CIT277", this); Will //hide query
    return dialog;
}

public boolean canGoBatchJournal()
{
    return true;
}

public void new()
{
    super();
    queryRun = new SysQueryRun(querystr(SalesFactoringQuery));
}

public container pack()
{   
    return [#CurrentVersion, queryRun.pack()];
}
public QueryRun queryRun()
{
    return queryRun;
}
boolean unpack(container packedClass)
{

    Integer             version        = conpeek(packedClass,1);
    container           packedQuery;

    switch (version)
    {
        case #CurrentVersion:
            [version,packedQuery] = packedClass;
            if (packedQuery)
                queryRun = new SysQueryRun(packedQuery);
            break;

        default:
            return false;
    }
    return true;
}
public boolean validate(Object _calledFrom = null)
{
    if (false)
        return checkFailed("");

    return true;
}

public static SalesFactoringBatch construct()
{
    return new SalesFactoringBatch();
}

public static void main(Args _args)
{
    SalesFactoringBatch _salesFactoringBatch;
    _salesFactoringBatch = SalesFactoringBatch::construct();
    if(_salesFactoringBatch.prompt())
    {
        _salesFactoringBatch.run();
    }
}
public void initParmDefault()
{

    Query query;
    ;
    super();
    query = new Query(queryStr(SalesFactoringQuery));
    queryRun = new QueryRun(query);
}
public boolean showQueryValues()
{
    boolean ret;
    ret =  true;
    return ret;
}
public ClassDescription caption()
{
//To get caption
    return "@NCC124";

}


http://daxtechies.blogspot.in/2013/12/dialog-in-ax-2012-multiselect-control.html

https://community.dynamics.com/ax/b/dynamicsaxinsightbyanas/archive/2015/04/22/ax-2012-add-lookup-to-batch-job-dialog

Use of container in display method in AX

Use of container in display method in AX

There may be requirement when we need to display certain things from multiple lines in to a single field
 with comma separated, and it is just for viewing purpose(Sometime informative).
Ex:
In sales header you want to capture all the lines warehouses in a single field which should be separated in
 comma.
Am going to add display method, Just add the below code in Table > SalesTable

Display Name Warehouse()
{
    salesline salesline;
    Container warehouse;
    int i=0;
    str strwarehouse;
    ;
    strwarehouse='';
    while select salesline where salesline.SalesId==this.SalesId
    {
        if(confind(warehouse,InventDim::find(salesline.InventDimId).InventLocationId)==0)
            warehouse +=InventDim::find(salesline.InventDimId).InventLocationId;
    }
     for (i = 1 ; i <= conLen(warehouse) ; i++)
     {
        if(strwarehouse=='')
        strwarehouse=conPeek(warehouse,i);
        else
        strwarehouse=strwarehouse+', '+conPeek(warehouse,i);

     }
    return strwarehouse;
}

And then drag this particular method in SalesTable form.


And once this display method is added in to the grid, we will be able to view our scenario.
Here it is:


So, the field ‘warehouse’ in header part of sales order represents the cumulative warehouse of lines.

X++ Code to Export AOT Object / automatic backup of XPO's.



Following job illustrates how to export/backup all AOT Classes object.

void ExportTreeNodeExample()
{
    TreeNode            treeNode;
    FileIoPermission    perm;

    #define.ExportFile(@"D:\AOTclasses.xpo")
    #define.ExportMode("w")
    ;

    perm = new FileIoPermission(#ExportFile, #ExportMode);
    if (perm == null)
    {
    return;
    }
    perm.assert();

    treeNode = TreeNode::findNode(@"\Classes");
    if (treeNode != null)
    {

    // BP deviation documented.
    treeNode.treeNodeExport(#ExportFile);
    }

    CodeAccessPermission::revertAssert();

}