[Axapta]带参数的RunbaseReport最佳实践

AX中RunbaseReport类用来运行一个报表,它可以定义一些参数,在弹出对话框的时候设置这些参数,以列出工单为例,先看看不考虑从其他form点击纪录带入参数的时候如何实现这个报表。下图是所用到的几个对象:

菜单项TestProdReport指向类TestProdReport,下面是类TestProdReport的代码:

class TestProdReport extends RunbaseReport
{
    NoYesId     showOnlyOpen;
    DialogField dfShowOnlyOpen;

    #define.CurrentVersion(0)
    #localmacro.CurrentList
        showOnlyOpen
    #endmacro
}

static void main(Args args)
{
    TestProdReport prodReport = new TestProdReport();
    ;

    if (prodReport.prompt())
        prodReport.run();
}

public identifiername lastValueElementName()
{
    return reportStr(TestProdReport);
}

public NoYes parmShowOnlyOpen(NoYes _showOnlyOpen = showOnlyOpen)
{
    showOnlyOpen = _showOnlyOpen;

    return showOnlyOpen;
}

public Object dialog(DialogRunbase dialog, boolean forceOnClient)
{
    DialogRunbase   ret;
    ;

    ret = super(dialog, forceOnClient);
    dfshowOnlyOpen = ret.addFieldValue(typeid(NoYesId),showOnlyOpen,"Show only open orders");

    return ret;
}

public boolean getFromDialog()
{
    boolean ret;

    ret = super();

    showOnlyOpen = dfShowOnlyOpen.value();

    return ret;
}

public container pack()
{
    return [#CurrentVersion, #CurrentList] + [super()];
}

public boolean unpack(container packedClass)
{
    container       base;
    boolean         ret;
    Integer         version    = RunBase::getVersion(packedClass);
    boolean         dummy;

    switch (version)
    {
        case #CurrentVersion:
            [version, #CurrentList, base] = packedClass;
            ret = super(base);
            break;
        default:
            ret = false;
    }

    return ret;
}

报表TestProdReport的代码:

public class ReportRun extends ObjectRun
{
    TestProdReport  testProdReport;
}

public void init()
{
    ;

    testProdReport = this.args().caller();

    super();


}

public boolean send(Common _cursor, int _level=1, boolean _triggerOffBody=TRUE, boolean _newPageBeforeBody=FALSE)
{
    boolean     ret;
    ProdTable   _prodTable;
    ;

    if(_cursor.TableId==tablenum(ProdTable))
    {
        _prodTable = _cursor;
        if(testProdReport.parmShowOnlyOpen() && _prodTable.ProdStatus==ProdStatus::Completed)
            return true;
    }

    ret = super(_cursor, _level, _triggerOffBody, _newPageBeforeBody);

    return ret;
}

这里我们是在报表的Send函数判断工单状态根据条件过滤掉已关闭的工单,这不是最好的办法,因为Query仍会查询出所有的工单纪录,在一定程度上影响性能,更好的办法是重载fetch方法,在fetch方法中获取报表的query,在query中根据条件加入对ProdStatus的过滤条件,再由Query创建QueryRun,运行QueryRun获取ProdTable纪录Send,这里就不再演示了。

现在的问题是如果把TestProdReport菜单项添加到ProdTable form中,在ProdTable form上点击这个菜单只显示当前ProdTable纪录到报表该如何来做呢?

首先在TestProdReport类定义中添加变量来纪录form中的当前纪录:

ProdTable   prodTable;

添加parmXXX函数来传入这条ProdTable纪录:

public ProdTable parmProdTable(ProdTable _prodTable = prodTable)
{
    ;
    prodTable = _prodTable;

    return prodTable;
}

添加函数initFromArgs来从传入的Args初始化这条纪录:

private void initFromArgs(Args args)
{
    ;
    if ( args && args.dataset())
    {
        switch(args.dataset())
        {
            case(tablenum(ProdTable)) :
                this.parmProdTable(args.record());
                break;
            default:

         }
        this.makeReportRun(); //创建ReportRun对象
        this.initQueryRun();  //初始化Report的QueryRun,必须是手工调用,正常运行报表是不会调用这个函数的,它调用后面的initQuery
    }
}

添加initQuery函数来初始化Query,initQuery函数会被initQueryRun()调用,在这里我们根据传入的ProdTable纪录根据主键工单号ProdId来过滤:

public Query initQuery()
{
    QueryBuildDataSource    queryBuildDataSource;
    QueryBuildRange         queryBuildRange;
    Query                   query;
    ;
    query = super();

    queryBuildDataSource = query.dataSourceTable(tablenum(ProdTable));
    if (!queryBuildDataSource)
        queryBuildDataSource = query.addDataSource(Tablenum(ProdTable));

    queryBuildRange = queryBuildDataSource.findRange(fieldnum(ProdTable, ProdId));
    if (!queryBuildRange)
        queryBuildRange = queryBuildDataSource.addRange(fieldnum(ProdTable, ProdId));

    if (prodTable)
        queryBuildRange.value(prodTable.ProdId);//根据工单号来筛选

    return query;
}

最后修改main函数,调用initFromArgs来初始化就可以了:

static void main(Args args)
{
    TestProdReport prodReport = new TestProdReport();
    ;
    prodReport.getLast();
    prodReport.initFromArgs(args);
    if (prodReport.prompt())
        prodReport.run();
}

注意这里在调用initFromArgs函数之前调用了一次getLast(),如果不在这里调用一次getLast(),后面的prompt()会在内部调用一次getLast(),把上一次pack的query读入,显示出来的对话框中看到的是上一次的内容,也就把initFromArgs()创建的Query的给覆盖了,所以这里先调用一次getLast(),prompt()会看到这个函数已经调用过了就不再调用了,所以这行是必须的。当前纪录的工单号相应的会出现在对话框中的过滤选项内:

以上就是如何在报表中根据form的当前纪录来过滤的实现办法。这里还要说一个runbaseReport的initParmDefault()函数,它是在第一次运行报表时会被调用,一旦有pack/unpack成功之后就不会在调用,在这里可以针对报表的第一次运行做一些初始化的工作,针对我们的这个报表是不需要的。

再把我们的这个例子扩展开,如果说在ProdTable form中选中了多条纪录,要在报表上打印出这多条纪录又该怎么办呢?

我们调用传入纪录的isFormDataSource()来判断是否来自于form的DataSource,如果是则使用common.Datasource()方法获得formDataSource,再使用formDatasource.getFirst(true)、formDatasource.getNext()轮询获取选中纪录的主键,然后设置到Query的Range中就可以了。基本结构是一样的,这里就不再演示了,下面的链接可以下载这个演示的project,从AXAPTA 3.0系统导出:https://files.cnblogs.com/duanshuiliu/TestProdReport.zip

原文地址:https://www.cnblogs.com/duanshuiliu/p/2586051.html