tceic.com
学霸学习网 这下你爽了
赞助商链接
当前位置:首页 >> IT/计算机 >>

Dynamics Ax开发笔记


目 录
1、16 进制转换为 10 进制的方法 ...................................................................................... 3 2、Agrs Class 简介 ................................................................................................................ 3 3、Args 传值 ......................................................................................................................... 4 4、Ax2009 去掉内容界面列表 ............................................................................................ 5 5、Axapta 中主 Form 和子 Form 间值的传递 .................................................................... 6 6、Ax 实现多线程操作 ........................................................................................................ 7 7、Common 应用举例 ......................................................................................................... 8 8、display 方法.................................................................................................................... 8 9、distinct 功能的实现 ........................................................................................................ 9 10、Form 传 container 类型参数到另一个 form? ......................................................... 10 11、Form 的 Datasource 方法说明 ................................................................................... 11 12、Form 上控件状态的保存和复取................................................................................ 12 13、Grid 字段的动态设定和查询 ..................................................................................... 13 14、Map 的使用................................................................................................................. 13 15、query 使用举例........................................................................................................... 15 16、QueryBuildRange 的空值使用 .................................................................................... 17 17、QueryBuildRange 使用值及表达式过滤 .................................................................... 18 18、Query 条件 .................................................................................................................. 25 19、Reaseach,Refresh 和 reRead 的区别 .......................................................................... 26 20、TableId RecId 的使用方法 .......................................................................................... 26 21、this 和 Form 的区别.................................................................................................... 27 22、X++中的字符串操作函数 ........................................................................................... 27 23、不同表,但结构相同的表的数据复制 ........................................................................ 30 24、不用 Query 查询的另外一种方法 ............................................................................. 31 25、创建自己的 Number Sequence 引用模块 ................................................................ 32 26、得到过滤条件的条件值 ............................................................................................. 35

27、得到一个扩展类型的属性 ......................................................................................... 35 28、动态的创建表结构 ..................................................................................................... 36 29、多条记录的传递 ......................................................................................................... 37 30、分号;在 Ax 编译器中的作用 ...................................................................................... 38 31、根据名称来判断一个表是否存在 ............................................................................. 39 32、更改当前的公司 ......................................................................................................... 39 33、公司的 LOGO 图片如何在报表头显示..................................................................... 39 34、关于系统中各个方法执行顺序的讨论 ..................................................................... 40 35、获得当前用户的相关信息 ......................................................................................... 41 36、两个表之间建立 Query .............................................................................................. 41 37、临时表的应用 ............................................................................................................. 42 38、判断某个用户是否属于某个组 ................................................................................. 43 39、强制同步表 ................................................................................................................. 44 40、清除数据库缓存 ......................................................................................................... 45 41、取得当前窗体 Data Source 的表名? ...................................................................... 45 42、如何把 Form 上显示的值传到 report 中打印? ...................................................... 46 43、如何遍历报表 ............................................................................................................. 46 44、如何改小数位 ............................................................................................................. 47 45、如何取得 AX 的安装路径?....................................................................................... 47 46、如何用代码清除 query 中所下的过滤条件? .......................................................... 48 47、如何在一个窗体中关闭另一个窗体 ......................................................................... 50 48、实现定时关闭 Form ................................................................................................... 50 49、实现动态跳转 ............................................................................................................. 51 50、使用 X++建一个 Project ............................................................................................. 52 51、在 AX 中实现 Not like 的三种常用方法 .................................................................... 52 52、怎样在下拉框中显示有过滤条件的数据 ................................................................. 53

1、16 进制转换为 10 进制的方法
class globel::hex2int() static int hex2Int(str 12 hex) { int res = 0; int d = strLen(hex); int i = 1; int char; int largeA = char2num('A',1); int largeF = char2num('F',1); int zero = char2num('0',1); int nine = char2num('9',1); hex = strUpr(hex); while (i <= d) { char = char2num(hex,i); res = res * 16; if ((char >= zero) && (char <= nine)) res += (char - zero); else if ((char >= largeA) && (char <= largeF)) res += (char - largeA + 10); else return 0; i++; } return res; }

2、Agrs Class 简介
转自:http://farseer1215.cnblogs.com/archive/2006/06/07/419330.html 这个类在很多代码中出现,在启动报表的时候也需要用到它. 简单来说这个类用于共享构造参数.在 Axapta 中之所以可以用 Args 的方式,是因为: 1.通常参数的数目比较少. 2.用的参数类型很类似. 3.有时候构造一个主要的对象,需要构造与之相关的对象,在构造这些对象时需要用到相 同的构造参数. 在传统的 OO 世界里,一个对象往往有多个重载的构造函数,通常情况下这没什么问题,但 当一个主要的对象需要通过特定构造器去构造相关的对象时,事情变得糟糕起来.有时候需要 通过逻辑判定到底该构造哪个构造函数,并且要在很多层之间传递这些信息.事实证明在 Axapta 中,很多报表,窗体,Action 类的构造参数都是很类似的,于是 Axapta 采用了单一的 Args

对象来传递参数,它封装了最常用的几个参数. 属性 类型 描述 caller object 创建 Args 的对象的引用 dataset tableid 待查找字段或者记录指向的表,通常情况下为 null,大多数情况下 dataset 是隐式的. designName str 将采用报表的哪个设计,如为 null 则用默认设置. lookupField Fieldid 当显示窗体时,用于过滤记录的字段 loopupValue Str 当显示窗体时,过滤字段对应的值. menuitemName Str 引起对象创建的菜单名称 menuitemType Str 引起对象创建的菜单类型 Name Str 对于 Form 和 Report 指触发 Form 和 Report 的菜单名称 parentWnd Int 不常用,可以不予理会. Parm Str 一般的字符串参数 parmenumType int 基本枚举类型的 ID,通常会使用 enumnum(some-type)函数 parmenum int 通过 paramnumType 指定的一个基础枚举类型的值.通常结合 parmenumType 选择不同的行为. paramObject Object 一般的 object 类型 Record common dataset 的一条空记录,可以用 DictTable.makeRecord 来创建.

3、Args 传值
有需要的兄弟一起分享: { Container cData; ContainerClass cClass; Formrun formRun; Args args = new Args(); ; cData = [st1,int1,boolean1];//container 内容

cClass = new ContainerClass(cData);//创建 ContainerClass args.parmObject(cClass);//ContainerClass 作为一个对象传过去 args.name(formstr(formname)); formRun = classFactory.formRunClass(args); formRun.init(); formrun.run(); formrun.wait(); }

取得 { ContainerClass _ContainerClass; container containerData; ; if(element.args() && element.args().parmObject()) { _ContainerClass = element.args().parmObject();//取得对象 containerData = _ContainerClass.value();//取得 class 中的数据为 container 类型,用时直接从 container 中取即可 }

4、Ax2009 去掉内容界面列表
static void TEST_HideContentFrame(Args _args) { #WinApi HWND contentPane = WinApi::findWindowEx(WinAPI::findWindowEx(infolog.hWnd(), 0, 'MDIClient', ''), 0, 'ContentFrame', '' ); ; if (contentPane) WinApi::ShowWindow(contentPane, #SW_HIDE); }

5、Axapta 中主 Form 和子 Form 间值的传递

主 Form

子 Form 如上图所示,在主 Form 中单击“GetCoder”按钮打开子 Form,然后在子 Form 中申请 得编码后,单击“OK”按钮关闭子 Form,并将申请得的编码写入到主 Form 的“物料编码” 字段中。 实现步骤: 1、 在主 Form 中声明变量:str Coder; 2、 在主 Form 中定义方法: void setCoderValue(str newCoder) { Coder = newCoder; } 3、 给“GetCoder”按钮添加事件: void clicked() { args args; formrun formrun; ; args = new Args(formstr(UnifyCoder));

args.caller(Element); formRun = ClassFactory.formRunClass(args); formRun.init(); formRun.run(); ormRun.wait(); InventTable.ItemId = Coder; } 4、 给子 Form 的“OK”按钮添加事件: void clicked() { super(); element.args().caller().setcodervalue(UnifyCoder.GetCoder()); element.close(); } 经过以上几步的操作,原来预想的功能得以完全实现。

6、Ax 实现多线程操作
class ThreadDemo { static server void main() { Thread t; ; new ExecutePermission().assert(); //BP Deviation Documented t = new Thread(); t.run(classnum(ThreadDemo), staticmethodstr(ThreadDemo, run)); } static server void run(Thread t) { AsciiIo ai; // Change this to some path that your server will have access to str fileName = '\\t\\HelloWorld.txt'; ; sleep(5000); new FileIOPermission(fileName, 'w').assert(); //BP Deviation Documented ai = new AsciiIo(fileName, 'w'); ai.write('Hello World!');

} } static void ThreadDemoJob(Args _args) { ; ThreadDemo::main(); print 'Ok'; pause; }

7、Common 应用举例
BudgetMap parentLine() { DictTable dictTable = new DictTable(this.TransTableId); Common common; ; common = dictTable.makeRecord(); select common where common.RecId == this.TransRecId; return common; }

8、display 方法
1,display 方法是用来动态的显示一个值到 form 和 report 上的, 这个值可能是从数据库中来? ?2,必有函数的类型和返回的数据类型,并且二者必须相等; 3,这个值不能作为查找的过滤条件; 你的错误在于:你没有返回值,数据类型也不对。 改写如下: display name getTime() { return date2Str(systemdateget(),123,2,0,2,0,2); } 但是这样写, 令人迷惑, 函数值说是 name,但是返回值是当前时间, 我就不知道你需要什么。 假如需要当前时间的话,建议使用: display int getTime1()

{ return timeNow(); } 返回当前日期: display date getTime() { return systemdateget(); }

9、distinct 功能的实现
請問我想在 X++里要實現 SQL 的 distinct 去除重復的記錄,請問應該如何實現,另外建 立 Query 時是否可以去除重復的記錄,該如何操作? 可以的, 1,把数据源的属性 ordermode 设置为 group by; 2,把你要显示的字段都拖到 sorting 下; -------------------------------------------------------------------已经解决. server static boolean updatedate(PurchIdBase PurchIdBase , TEC_EDIOrder TEC_EDIOrder ) { TEC_EDICount TEC_EDICount; ; ttsbegin; select firstonly forupdate TEC_EDICount index hint Index1 where TEC_EDICount.PurchId == purchIdBase && TEC_EDICount.Tec_EDIOrder == TEC_EDIOrder; if(TEC_EDICount) { TEC_EDICount.Tec_CountEDI += 1 ; TEC_EDICount.doUpdate(); ttscommit; return true ; } ttscommit; return false ;

} -------------------------------------------------------------------奇怪,lz 的解决方法貌似不能实现你给的例子效果啊? 那个 1111 2222 用 group by 可以解决。 while select ItemId from trans group by ItemId { print trans.ItemId; } --------------------------------------------------------------------对,group by 就可以了 如果是在 Query 中可以这样写 Query query = new Query(); QueryBuildDataSource queryBuildDataSource; QueryBuildRange queryBuildRange; ?; queryBuildDataSource = query.addDataSource(tablenum(inventTrans)); queryBuildDataSource.sortClear(); queryBuildDataSource.addSortField(fieldnum(InventTrans, itemId)); queryBuildDataSource.orderMode(OrderMode::GroupBy); this.query(query); -------------------------------------------------------------------1、在 SQL 里用 Distinct 和 Group by 语句均可进行筛选重复记录! 2、在 AX 里用 FirstOnly---取结果集的第一条记录, Group by 语句对重复记录进行分组,达到去除重复记录的目的!

10、Form 传 container 类型参数到另一个 form?
用下面的代码就能实现了: Container cData; ContainerClass cClass; Formrun formRun; Args args = new Args(); cData = [st1,int1,boolean1]; cClass = new ContainerClass(cData); args.parmObject(cClass);//ContainerClass 作为一个对象传过去

args.name(formstr(formname)); formRun = classFactory.formRunClass(args); formRun.init(); formrun.run(); formrun.wait();

取得: ContainerClass _ContainerClass; container containerData; ; if(element.args() && element.args().parmObject()) { _ContainerClass = element.args().parmObject();//取得对象 containerData = _ContainerClass.value();//取得 class 中的数据为 container 类型, 用时直接 从 container 中取即可 }

11、Form 的 Datasource 方法说明
方法名称 Active 记录作为当前记录 执行时机 当用户移动鼠标选中某个记录时 说明 super()被调用,使选中的

Create 用户通过工具按钮或者快捷键(CTRL+N) 录的上面生成一条新记录; 创建一条记录时 当前记录的下面生成新记录 defaultMark 用户单击 Grid 控件左上角的标记区 一般用来复制或者删除所有记录用 Delete 用户删除一条记录 validateDelete() ,如果该方法返回 True 则执行删除操作 dislayOption 在一条记录显示前 执行该方法,一般被用来修改文本或者背景的颜色。

super()被调用,在当前记 如果 super(true);,则在

Grid 中的记录都被选中,

super()方法调用

在每一条记录显示前都会

exeuteQuery 当 Form 打开显示记录时 执行 query 来显示出数据

super()调用 Init()方法

Filter 用户通过快捷菜单激活过滤命令 增加一些信息可以在此增加一些代码

如果想在标准过滤功能中

First 光 标移 动到 数据 源的第一 条记 录 super()的调用使光标位于第一条记录处 Init super()方法调用 initValue 初始化值 当 Form 打开时 query 方法查询出数据并显示在 Form 中

通过

数据源的最基本的方法,

一条新记录已产生, 通过该方法初始化其 super()调用表的同名方法来 值

Last Leave leaveRecord linkActive 方法进行关联;

鼠标移动到最后一条记录 鼠标移到到一条记录时 光标的焦点移到一条新记录 数据源之间的关联 super()调用 executeQuery

12、Form 上控件状态的保存和复取
public class FormRun extends ObjectRun { Integer viewOptionValue; PrintPostCancel journalStatus; NoYesId journalPrinted; QueryBuildRange rangeStatus; QueryBuildRange rangePrinted; SysLastValue sysLastValue; #define.CurrentVersion(1) #localmacro.CurrentList viewOptionValue, journalStatus, journalPrinted #endmacro }

public void init() { super(); xSysLastValue::getLast(this); }

public void close() { ; xSysLastValue::saveLast(this); super(); } Form:CustInterestNote

13、Grid 字段的动态设定和查询
详细情况参看 AX4.0-主计划-查询-统计-物料需求统计(Form/ReqPoItemStatistic) 。 动态的查询: AX4.0-生产-工序清单

14、Map 的使用
Map 和 Maps 一、map 当作一个哈希表来用: Map mymap; mapEnumerator me; ; Mymap = new map(Types::String,Types::String); //以这样的格式添加数据 Mymap.insert(key,value); //获取遍历 Me = map.getEnumerator(); While(me.MoveNext()) {

Print me.currentKey() + me.currentValue(); } static void Job2(Args _args) { mapIterator mi; map mapC = new map(types::Integer,types::String); int i; while (i<=20) { mapC.insert(i,"aaa" + int2Str(i)); i++; } mi = new mapIterator(mapc); while ( mi.more()) { print mi.key(),"--", mi.value(); mi.next(); } pause; } 这是最基本的方法,有关方法请查看 MSDN 二、maps:在系统中不同的表可能会有一些相同属性的字段,而且这些字段的处理逻辑也 非常相似,但是他们的字段名可能完全不相同, 为了减少代码量可以使用 Maps,一下是一个例子: 将创建一个 Map 映射到 CustTable 和 myTable 共有的字段 1. 在 AOT 的 Map 节点右击新建 Map,命名为“MyMap” 2. 将 EDT 中的 AccountNum, CustName, CustGroupId 和 CustCurrencyCode 拖入到 “MyMap”中 3. 保存并 RESTORE 4. 在“myMap”的 mapping 节点下新建映射,选择映射表为 CUSTTABLE,在映 射下选择映射字段,选择对应的字段进行关联,在 CUSTTABLE 中对应的字段有 accountNum, name, currency and custGroup. 5. 按照同样的方法添加 MyTable 6. 在“MyMap”的 Methods 方法下添加方法(测试用) : void listRecords(MyMap _myMap) { ; while select _myMap { info(strFmt("%1, %2", _myMap.accountNum, _myMap.custName));

} } 7. 保存 以下是一个用来打印用来初始化 MAPS 的记录的值: static void DataDic_TestMyMap(Args _args) { MyMap myMap; CustTable custTable; MyTable myTable; ; myMap.listRecords(myTable); } 注意这里 MAP 完全是被声明为一个表来使用的。 同样也可以这样使用: Tablename.mapsname::mapsmethos(parameter); 表名后边加点以后直接打上该表关联的 MAPS 名字,然后“:”号再加上 MAPS 的方法,括 : 号中传上参数。这样可以直接调用 MAPS 的方法来修改该表的数据。 还有一种用法,如: MyMap myMap; MyTable myTable; ; myMap = myTable; ttsbegin; select forupdate myMap; myMap.fields = value; ? myMap.insert(); ttscommit; 注意是一定要用事务的。

15、query 使用举例
As the name implies QueryRun is the executor of a query linked to it. To construct a query you want QueryRun to execute, you need build classes: Query QueryBuildDataSource QueryBuildRange QueryBuildFieldList QueryBuildLink QueryBuildDynaLink

Today’s example will use the first four to demonstrate a query that sums the credit limit field in CustTable grouped by Country and Currency. Additionally a count field indicates how many records are represented in the sum. Ranges are implemented for AccountNum and Country, but the user is allowed to add additional range criteria in the dialog. To demonstrate the status() property I have locked it, so the user can not change it. QueryRun QueryRun executes the query. If needed the familiar query dialog can be opened before the query is run. This is done using the prompt() method. SysQueryRun extends QueryRun and has a total of 7 prompt*() methods, with different default behavior. For example promptAllowAddRange() would allow the user to add new where-conditions. Query A query represents the select statement. This is where all the strings come together. QueryBuildDataSource Using QueryBuildDataSources you add all the tables you want joined (just one in this example). This is also where you define how the resultset is to be sorted. The orderMode() method lets you define OrderBy GroupBy QueryBuildRange Ranges represent where conditions. Multiple ranges are connected with AND conditions. Unfortunately there is no easy way to change that. QueryBuildFieldList Represents the selected fields of the query. By default all fields are selected. In regular queries you probably wouldn’t use them that often, but when grouping this is the way to define which fields are calculated. SelectionField is an enum with the following values Avg Count Database Max Min Sum

static void Job24(Args _args) { CustTable custTable; Query query = new Query(); QueryRun qr = new queryRun(query); QueryBuildDataSource qbds = qr.query().addDataSource(tableNum(CustTable)); QueryBuildRange qbrAccN = qbds.addRange(fieldNum(CustTable,AccountNum)); QueryBuildRange qbrCountry = qbds.addRange(fieldNum(CustTable,CountryRegionId)); QueryBuildFieldList qbfl = qbds.fields(); ; qbrAccN.value('4000..4050'); qbrAccN.status(RangeStatus::Locked); qbrCountry.value('US..中国'); qbfl.addField(fieldNum(CustTable,CreditMax),SelectionField::Sum); qbfl.addField(fieldnum(CustTable,RecId),SelectionField::Count); qbds.addSortField(fieldnum(CustTable,CountryRegionId)); qbds.addSortField(fieldNum(CustTable,Currency)); qbds.orderMode(OrderMode::GroupBy); if (qr.prompt()) { while (qr.next()) { custTable = qr.get(tableNum(CustTable)); print strfmt("%1 %2 %3 records)",custTable.CountryRegionId,custTable.Currency, num2str(custTable.CreditMax,10,2,0,0),custTable.RecId); } } pause; }

(%4

16、QueryBuildRange 的空值使用
在用 QueryBuildRange 的 value 属性时,如果 value 的值是‘’ ,则查询会忽略该 Range,好 像没有这个 Range 一样,比如如下语句: static void EmptyTest() {

Query q; QueryRun qr; CustTable cust; ; q = new Query(); q.addDataSource(tableNum(custtable)).addRange(fieldnum(custtable,accountnum)).value(''); qr = new QueryRun(q); while(qr.next()) { cust = qr.get(tablenum(custtable)); box::info(cust.Address); } pause; }如果想查询某个字段的值为‘’值的该怎么处理那?这就需要用到 SysQuery::valueEmptyString();如下所示: static void EmptyTest() { Query q; QueryRun qr; CustTable cust; ; q = new Query(); q.addDataSource(tableNum(custtable)).addRange(fieldnum(custtable,accountnum)).value(SysQu ery::valueEmptyString()); qr = new QueryRun(q); while(qr.next()) { cust = qr.get(tablenum(custtable)); box::info(cust.Address); } pause; }

17、QueryBuildRange 使用值及表达式过滤
在开始使用 QueryBuildRange 进行与、或、等于等关系时,并不是想象中那么简单,本文章 结合网络上的资料和我自己的实践总结了一些 queryBuildRange 值及表达式的使用方法。

一.

单一值作为过滤条件,如

Select inventtable where itemid = “aa” 可以使用如下代码 static void job99() { Query QueryBuildRange QueryBuildDataSource QueryRun str str InventTable ;

query; qbr; qbds; qr; qs; s; inventTable;

qs = '"CW"'; query = new Query(); qbds = query.addDataSource(tablenum(InventTable)); qbr = qbds.addRange(fieldnum(InventTable,ItemId)); qbr.value(qs); qr = new QueryRun(query); while(qr.next()) { inventTable = qr.get(tablenum(InventTable)); s = s + inventTable.ItemId + ' '; } print s; pause; } 这里需要注意一点,如果是字符串型的值,一般用( “)将值括起来,如果是数,则不需要, 对于枚举需要转换成整数。 二. 使用两个不同字段的值以并的关系过滤,如

Select inventDim where color=”Gold” and size = “30” 只需要建立两个 Range 并分别添加过滤条件,如下: static void Job55(Args _args)

{ Query QueryBuildRange QueryBuildDataSource QueryRun str str str InventDim ; query; qbr; qbds; qr; qscolor; qssize; s; inventDim;

qscolor = '"Gold"'; qssize = '"30"'; query = new Query(); qbds = query.addDataSource(tablenum(InventDim)); qbr = qbds.addRange(fieldnum(InventDim,InventColorId)); qbr.value(qscolor); qbr = qbds.addRange(fieldnum(InventDim,InventSizeId)); qbr.value(qssize); qr = new QueryRun(query); while(qr.next()) { inventDim = qr.get(tablenum(InventDim)); s = s + InventDim.InventDimId + ' '; } print s; pause; } 三、最简单也是最方便的或,如 Select inventTable where itemId = “aa” or itemId = “11” 可以使用如下代码: static void Job22(Args _args) { Query QueryBuildRange QueryBuildDataSource QueryRun str

query; qbr; qbds; qr; qs;

str InventTable ;

s; inventTable;

qs = '"cw","11"'; query = new Query(); qbds = query.addDataSource(tablenum(InventTable)); qbr = qbds.addRange(fieldnum(InventTable,ItemId)); qbr.value(qs); qr = new QueryRun(query); while(qr.next()) { inventTable = qr.get(tablenum(InventTable)); s = s + inventTable.ItemId + ' '; } print s; pause; }

四、实现字段间的或、与及组合过滤,如实现: Select inventTable where itemId = “aa” or itemName = “admin” 首先需要给 QueryBuildDataSource 添加一个 Rrange,具体添加那一个字段都可以, 然后 方法有三: 方法一: Range 的 value 需要满足以下条件: 1.整个表达式必须要' '引起来而不是" "; 2.这个表达式必须用()括起来; 3.每个子表达式必须用各自的()括起来; 4.对于当前表中的字段,用字段名直接引用即可; 5.对于其他表中的字段,引用时需要添加 DataSource Name 作为前缀; 6.string 类型的值需要用" "引起来,也可包含在 queryValue()中;

7.枚举类型的值需要用对应的 int 类型指定; 8.Date 类型的值需要用 Date2StrXpp()转化 代码如下: static void Job23(Args _args) { Query QueryBuildRange QueryBuildDataSource QueryRun str str InventTable ; qs

query; qbr; qbds; qr; qs; s; inventTable;

= strfmt('((%1== "%2") || (%3=="%4"))', fieldStr(inventTable,ItemId),"cw", fieldStr(inventTable,ItemName),"电池组 1");

query = new Query(); qbds = query.addDataSource(tablenum(InventTable)); qbr = qbds.addRange(fieldnum(InventTable,ItemId)); qbr.value(qs); qr = new QueryRun(query); while(qr.next()) { inventTable = qr.get(tablenum(InventTable)); s = s + inventTable.ItemId + ' '; } print s; pause; } 方法二: 字符串还是需要用 “ “ 括起来,其它符号用 ‘ ‘ 括起来,注意事项如方法一 static void Job23(Args _args) {

Query QueryBuildRange QueryBuildDataSource QueryRun str str InventTable ;

query; qbr; qbds; qr; qs; s; inventTable;

qs= '(' + fieldid2name(tablenum(inventTable),fieldnum(inventTable,Itemid))+ ' == '+ '"11"' +'\") '=='+'"aa"'+')'; || ('+fieldid2name(tablenum(inventTable),fieldnum(inventTable,itemId))+

query = new Query(); qbds = query.addDataSource(tablenum(InventTable)); qbr = qbds.addRange(fieldnum(InventTable,ItemId)); qbr.value(qs);

qr = new QueryRun(query); while(qr.next()) { inventTable = qr.get(tablenum(InventTable)); s = s + inventTable.ItemId + ' '; } print s; pause; } 方法三: 来自系统的标准方法,另一种表达方式,系统路径:Forms-->Adress-->DataSource Method addQuerySalesQuotationTable void addQuerySalesQuotationTable(SalesQuotationTable { QueryBuildDataSource CustTable queryBuildDataSource; custTable; _salesQuotationTable)

str ; queryBuildDataSource custTable

queryExpression;

= this.query().dataSourceTable(tablenum(Address)); = CustTable::Find(_salesQuotationTable.CustAccount);

queryExpression = &apos;(((&apos; + tableid2name(tablenum(Address)) fieldid2name(tablenum(Address), fieldnum(Address, AddrTableId)) + + &apos;.&apos; +

&apos; == &apos; + queryValue(_salesQuotationTable.TableId) + &apos;) && (&apos; + tableid2name(tablenum(Address)) fieldid2name(tablenum(Address), fieldnum(Address, AddrRecId)) + + &apos;.&apos; +

&apos; == &apos; + queryValue(_salesQuotationTable.RecId) + &apos;)) || ((&apos; + tableid2name(tablenum(Address)) fieldid2name(tablenum(Address), fieldnum(Address, AddrTableId)) + + &apos;.&apos; +

&apos; == &apos; + queryValue(custTable.TableId) + &apos;) && (&apos; + tableid2name(tablenum(Address)) fieldid2name(tablenum(Address), fieldnum(Address, AddrRecId)) + + &apos;.&apos; +

&apos; == &apos; + queryValue(custTable.RecId) + &apos;)))&apos;;

queryBuildDataSource.addRange(fieldnum(Address, Address)).value(queryExpression);

}

18、Query 条件
QueryBuildRange “交” 条件查询 不同字段 精确 queryExpression = '(InventTable.ItemName == "座") && (InventTable.ItemGroupID == "10")'; qbds.addRange(fieldnum(InventTable, ItemId)).value(queryExpression); 模糊 queryExpression = '(InventTable.ItemGroupID == "10")'; qbds.addRange(fieldnum(InventTable, ItemId)).value(queryExpression); qbds.addRange(fieldnum(InventTable, ItemName)).value("*座*"); 相同字段 qbds.addRange(fieldnum(InventTable, ItemName)).value("c*001"); ItemId like 'c*' and itemid like '*001' “并”条件查询 不同字段 精确 queryExpression = '(InventTable.ItemGroupID == "20") ||(ItemName == "座")'; qbds.addRange(fieldnum(InventTable, ItemId)).value(queryExpression); 模糊 可能没有直接的办法实现 相同字段 精确 queryExpression = '20,10'; qbds.addRange(fieldnum(InventTable, ItemGroupId)).value(queryExpression); 模糊

queryExpression = '*座,00*'; qbds.addRange(fieldnum(InventTable, ItemId)).value(queryExpression

19、Reaseach,Refresh 和 reRead 的区别
这三个都是数据源的方法,意思又有些相似,所以不少人有些模糊。 ReSearch():在保留当前的条件下,包括过滤条件、排序等,从数据库中重新刷新数据 源的数据;若要改变查询条件或者排序条件,我们应该使用 executeQuery 而不是 ReSearch () ; Refresh() 重新从数据源中读取当条记录。 : Reread() 重新从数据库中读取当条记录。 : 开发文档里有详细解释,请参考:Methods on a form data source 类似的还有 doupdate 和 update 方法,也有些会让人误解. update 方法是执行表的 update 的方法,而 doupdate 方法则不执行表里的 update 方法, 直接 update 数据库.好像论坛的什么地方有一个详细解释的贴.

20、TableId RecId 的使用方法
SysDictTable dictTable; WebLink webLink = new WebLink(); PurchTable PurchTableTmp; xtTCardTable xtTCardTableTmp; if(element.args().dataset()) { actualCommon = element.args().record(); actualTableId = actualCommon.TableId; actualRecId = actualCommon.RecId; dictTable = new SysDictTable(actualTableId); //select purchTable where purchTable.RecId == actualRecId; }

select actualCommon where actualCommon.RecId == actualRecId; if(actualCommon) { if(actualCommon.(dictTable.fieldName2Id("approveState")) xtApproveState::Open) { } else { wmf = WebUrlMenuFunction(weburlitemstr('xtEPAuditingCurHistoryInfo')); webLink.menufunction(wmf); webLink.record(actualCommon); url = webLink.url(false); webSession().redirectURL(url); } }

==

new

21、this 和 Form 的区别
在 Form 中 this 和 element 小有区别, element 的包容性似乎比 this 大一点, 所以在 form 和 report 中推荐使用 element,使用 this 可能会出现一些意想不到的错误(曾经遇到这样的 问题,将 this 换成 element 就 OK 了) 。在 Class 和 table 中一般使用 this,分别表示当前类和 当前记录;

22、X++中的字符串操作函数
1.strlen(str text) 作用:获取字符串的长度 参数:text,待获取长度的字符串 返回值:字符串的长度

static void strlenExample(Args _args) { str source; int i ; ; source = "Axapta"; i = strlen(source); print i;

pause; } 2.strfind(str source,str toFindCharacters,int position ,int number) 作用:发现某个字符的位置 参数:source 源字符串 toFindCharaters:待发现的字符 position:开始搜索的位置 number:搜索字符的个数 返回值:字符的位置

static void strfindExample(Args _args) { str source; str destination; int i ; ; source = "Axapta Axapta"; destination = 'x'; i = strfind(source,destination,3,100); print i; pause; }

3.strins(str source ,str toInsertStr,int postion) 作用:在源字符串的指定位置插入字符串 参数:source 源字符串 toInsertStr 待插入的字符串 postion 插入字符串的位置 返回值:插入字符串后的字符串

static void strinsExample(Args _args) { str source; str destination; int i ; ; source = "Axapta Axapta"; destination = ' Axapta'; source = strins(source,destination,7);

print source; pause; } 4.strdel(str source,int postion,int number) 作用:从指定位置开始在源字符串中删除指定长度的字符 参数:source 源字符串 postion 删除的开始位置 number 删除字符的个数 返回值:删除指定字符后的字符串

static void strdelExample(Args _args) { str source; str destination; int i ; ; source = "Axapta Axapta"; source = strdel(source,1,7); print source; pause; } 5.strLFix,strRFix 这个难得说清楚,看代码吧,一看就明白了。 static void SpecialQueryBuild2() { str newStr; ; newStr = strLfix(int2str(8),10,"0"); print(newStr); newStr = strRfix(int2str(8),10,"0"); print(newStr); pause; } 6.strpoke(str text1,str text2, int position) 说明:覆盖 text1 中 position 开始的字符为 text2.

例子: strpoke('123456789','ABC',3) 返回的字符串是 '12ABC789' 7.strrem(str text1,str text2) 说明:在 text1 中移除 text2 中所提供的字符. 例子: strrem('ACBDEFGAEFGD','AF') 返回的值是:'CBDEGEGD'. 8.strLine(str text1,int counter) 说明: 返回 text1 中 counter 行的字符串. 例子: strtemp='SDFEG-jui\nkjedss\nuikjh344\n' strline(strtemp,1) 返回值是:'kjedss'.

23、不同表,但结构相同的表的数据复制
Static Common RecordCopy(Common _from,Common _to) { Dictionary dict; DictTable dictTableFrom; DictTable dictTableTo; DictField dictFieldFrom; DictField dictFieldTo; Integer recCnt; ; dictTableFrom = new DictTable(_from.TableId); dictTableTo = new DictTable(_to.TableId); for (recCnt = 1;recCnt <= dictTableTo.fieldCnt();recCnt ++) { dictFieldTo = dictTableTo.fieldObject(dictTableTo.fieldCnt2Id(recCnt)); if (!dictFieldTo.isSystem()) {

if (dictFieldTo.name() == "oldRecId") dictFieldFrom dictTableFrom.fieldObject(dictTableFrom.fieldName2Id("RecId")); else dictFieldFrom dictTableFrom.fieldObject(dictTableFrom.fieldName2Id(dictFieldTo.name())); if (dictFieldFrom && dictFieldFrom.type() == dictFieldTo.type()) { _to.(dictFieldTo.id()) = _from.(dictFieldFrom.id()); } } } return _to; }

=

=

注 : 此 功 能 不 修 改 系 统 的 程 序 , 只 增 加 一 个 类 :RecordOperation 。 调 用 RecordOperation::RecordCopy(from,to);就可以了。

24、不用 Query 查询的另外一种方法
1.在数据源创建一个方法: void findCaller() { TableTest tableTestTmp; SalesTable salesTableTmp = element.args().record(); ; select tableTestTmp where tableTestTmp.EmployeeId salesTableTmp.SalesResponsible; if (tableTestTmp.RecId) tableTest_ds.findRecord(tableTestTmp); } 2.在数据源的 executeQuery()方法中调用上述方法。 public void executeQuery() { tableTest_ds.findCaller(); super(); }

==

25、创建自己的 Number Sequence 引用模块
发表于 2006-4-15 10:03:00 作者:廖源 Daniel.Intelzon 我觉得 Axapta 中的 number Sequence 一直以来都是一个重点,现在就让我们尝试手工 创建一个 Number Sequence 引用模块: 实例中, 我们假设要做一个 SMS 的短信管理系统的主数据表 SMS_Content, 这个表中的 SMS_ContentId 我们需要指定一个 Number Sequence 来生成。步骤如下: 1.在名为 NumberSeqModule 的 BaseEnum 中增加一个值的名称为 SMS, 数值为当前最大 值加一; 2.创建一个用来装载 SMS 系统中使用 Number Sequence 的 numberSeqReference 子类,这里我命名为 NumberSeqReference_SMS。在这 个类中需要覆盖父类中的方法:LoadModule 和增加 一个用于返回在步骤一中定义好的枚举值的静态方法。 代码如下: public class NumberSeqReference_SMS extends numberSeqReference { protected void loadModule() { NumberSequenceReference numRef; ; numRef.configurationKeyId = 16001;//这里指定一个 Configuration Key,可以在 AOT 的 Data Dictionary 下面的 ConfigurationKeys 定义一个,我在这里 使用的是自己创建的 SMS,它的值为 16001 /* Setup SMS Content number */ numRef.dataTypeId = typeId2ExtendedTypeId(typeid(SMS_ContentId));//定义此 number Sequence 的数据类型是 SMS_ContentId 这个字段的数据 类型 numRef.referenceHelp = literalStr('@SMS151');//这里的 Label 定义了方便在引用的时候精确理解的帮助内容 numRef.wizardContinuous = true;//定义在通过向导生成 number sequence 的连续性

numRef.wizardManual = NoYes::No;//定义是否手动录入 number sequence 的值 numRef.wizardAllowChangeDown = NoYes::No;//定义是否允许把自动获取的 number sequence 的值改成更小的值 numRef.wizardAllowChangeUp = NoYes::No;//定义是否允许把自动获取的 number sequence 的值改成更大的值 numRef.wizardLowest = 1;//number Sequence 的最小值 numRef.wizardHighest = 9999999;//number Sequence 的最大值 numRef.sortField = 1;//在 SMS 模块中 number Sequence 中的排序值 this.create(numRef);//创建此 number Sequence 引用 } public static NumberSeqModule numberSeqModule() { return NumberSeqModule::SMS; } } 3.到 Class NumberSeqReference 中的 construct 方法中增加以下内容: case (NumberSeqReference_SMS::numberSeqModule()) : return new NumberSeqReference_SMS(_module); 位置是在系统已有的 case 语句块中,意思是让系统加载刚才我们自己的 number sequence 引用模块 4.到 Class NumberSeqReference 中的 moduleList 方法中增加以下内容: moduleList += NumberSeqReference_SMS::numberSeqModule(); 位置是在 return moduleList 之前的地方,意思是将我们自己的 number sequence 引用模块加入到系统的 moduleList 当中去 至此我们自己的 number Sequence 引用模块添加完毕。 接下来我们来考虑如何使用自己新增加的 number sequence 引用。 考虑到系统设计,SMS_ContentId 的新增和删除的动作直接放在 Table 层: 在表的 initValue 方法中加入以下代码新增序列值: NumberSeq numberSeq;//定义一个序列

SMS_Content sms_Content; ; numberSeq = NumberSeq::newGetNum(NumberSeqReference::findReference(typeId2ExtendedTypeId(typ eid(SMS_ContentId))), true);//实例化这个序列 sms_Content.SMS_ContentId = numberSeq.num();//获取当前的序列值 在表的 delete 方法中加入以下代码删除序列值: NumberSeq::release(NumberSeqReference::findReference(typeId2ExtendedTypeId(typeid(S MS_ContentId))).NumberSequence, sms_Content.SMS_ContentId); 至此我们先去 basic-Setup-Number Sequence-Number Sequence 中定义一个被我们定义好的引用来使用的序列,然后在 basic-Setup-Number Sequence-Reference 中找到 module 名为 SMS,reference 为我们刚才定义的 SMS_ContentId 的 Label 值的引用,定义这个引用的 序列。接下来我们就可以到 AOT-Data Dictionary-Tables-SMS_Content 的右键中找到 Add-ins, 然后选择 Table Browser , 点 击 新 增 和 删 除 按 钮 就 可 以 看 到 我 们 的 SMS_ContentId 值 是 由 numberSequence 自动生成的效果了。

使用系统标准的功能产生自己的 Sequence Number 第一步 ,在 Basic/setup/Number sequence/numberSequence 增加一个 Sequence 编号: 比如 'MySequence', from 1 to 9999999 format='######' 第二步,在 form 的数据源的 Create 方法中写: public void create(boolean _append = false) { NumberSeq _numberSeq;//declare a NumberSeq variable ; super(_append); _numberSeq = numberSeq::newGetNumFromCode('MySequence',true,false); CurrentSequenceNo=_NumberSeq.num();

}

26、得到过滤条件的条件值
public void init() { formdatasource formdatasource; QueryBuilddatasource inventTransQuery; ; super(); if(element.args().caller()) { formdatasource = element.args().record().dataSource(); } inventTransQuery formdatasource.queryRun().query().dataSourceTable(tablenum(InventTrans)); info(inventTransQuery.findRange(fieldNum(InventTrans, DatePhysical)).value()); } =

27、得到一个扩展类型的属性
static void TestJob(Args _args) { Dictionary dict; DictType dictType; ; dict = new Dictionary(); dictType = dict.typeObject(dict.typeName2Id(extendedtypestr(AccountName))); info(strfmt("Name : %1 \nId: %2 \nStringLength: %3 \nAdjustment: %4 \nLabel: %5 \nHelp: %6 \nBasetype: %7", dictType.name(), dictType.id(), dictType.stringLen(), dictType.stringRight() ? "Right" : "Left", dictType.label(), dictType.help(), int2str(dictType.baseType()) + " - " + enum2Value(dictType.baseType()))); }

28、动态的创建表结构
static void AtuoCreateTable(Args _args) { AOTTableFieldList ATFL Dictionary\\Tables\\myTable\\Fields'); xInfo xInfo = new xInfo(); treeNode nodeTable Dictionary").AOTfindChild("Tables"); treeNode nodeTable1 Dictionary").AOTfindChild("Tables"); treeNode childNode; treenodeIterator nodeIterator; str properties; str fields; ; // 新建表 nodeTable = nodeTable.AOTfindChild("myTable"); if(!nodeTable) nodeTable.AOTadd("myTable"); // 新建字段 if (!ATFL.AOTFindChild('NewEnum')) ATFL.addEnum('NewEnum'); if (!ATFL.AOTFindChild('PostedDate')) ATFL.addDate('PostedDate'); // 修改属性 /*nodeIterator = nodeTable.AOTiterator(); childNode = nodeIterator.next(); while (childNode) { fields = childNode.treeNodeName(); = xInfo.rootNode().AOTfindChild("Data

=

infolog.findNode('\\Data

=

xInfo.rootNode().AOTfindChild("Data

if (fields == 'Field1') { properties = setProperty(childNode.AOTgetProperties(), "Label","New label"); childNode.AOTsetProperties(properties); break; } childNode = nodeIterator.next(); }*/ nodeTable1.AOTsave(); nodeTable1.AOTrefresh(); }

29、多条记录的传递
我有用 args.record(),传了一个我在 FORM 中选中的一条记录,当我在 FORM 中选了多条 记录时,用什么语句来实现? 假设是你的 FORM 里有和个表:T1 你选了多条记录. 你在接收方里 FormDataSource FormRun T1 t1; ; fr = args.caller(); tTmp = fr.dataSource(); for (t1 = tTmp.GetFirst(1) ? tTmp.GetFirst(1) : args.record();t1;tTmp.GetNext()) { ...自已的一些语句..... } fr; tTmp;

下面这个例子,来自偶博客里面的那个记帐凭证代码里面: FormDataSource TempDataSource; Common common; ; if ( element.args().parmEnum() == zyj_reportentrystyle::SelReport ) { TempDataSource = element.args().record().dataSource(); for (common=TempDataSource.getFirst(true) //取选中记录 ? TempDataSource.getFirst(true) : element.args().record();common;common=TempDataSource.getNext()) { element.insertlist(common); } } else if ( element.args().parmEnum() == zyj_reportentrystyle::AllReport ) { TempDataSource = element.args().record().dataSource(); for (common=TempDataSource.getFirst() //取全部数据 ? TempDataSource.getFirst() : element.args().record();common;common=TempDataSource.getNext()) { element.insertlist(common); } }

30、分号;在 Ax 编译器中的作用
我们会发觉有些时候,不用分号,代码也能编译通过,可是有些时候却会带来错误。那 么分号有什么作用呢? 因为 Ax 中,变量名可以和对象名相同,那么 ax 就不知道哪里是变量声明,哪里是变量 调用,比如可以声明一个 InventTable 的变量。这样系统就使用分号来区分。 所以,为了统一代码,避免莫名其妙的错误或者疏漏,我建议,不管方法有没有使用到 和对象相同的变量,都在声明之后加分号,即使没有变量声明,也在最前面加分号,这毕竟 是 ax 的特点。 当代码部分的第一行是 Axapta 的 sql 语句的时候,加分号与不加分号时,性能是没有差 异的;其他情况下,如果不加分号,即使编译没有出错,也会有性能上的差异。

31、根据名称来判断一个表是否存在
static server boolean checkTableName(str 50 _str) { Dictionary dictionary ; int tableCnt ; int i ; TableId tableId ; ; dictionary = new Dictionary() ; tableCnt = dictionary.tableCnt(); for (i = 1 ; i <= tableCnt ; i++) { tableId = dictionary.tableCnt2Id(i) ; if ( _str == dictionary.tableName(tableId) ) { return true ; } } return false ; }

32、更改当前的公司
changecompany()似乎只是能把下面的操作按哪个公司计算而已,但是不能改变当前的 公司,有什么方法可以改变当前的公司呢? DataAreaId dataarea DataAreaId = curExt(); dataarea;

//appl.setDefaultCompany(DataAreaId); appl.setDefaultCompany(dataarea.id,false); SysSecurity::reload(false); infolog.runStartupMenu();

33、公司的 LOGO 图片如何在报表头显示
在公司信息设置完公司的 LOGO 图片后, 如何在报表头显示出来?那段代码是怎么写的 呀?

display bitmap logo() { companyinfo ci; bitmap zml; ; zml = (select companyinfo).logo; return zml; } return companyinfo::find().logo;

34、关于系统中各个方法执行顺序的讨论
摘录自<Morphx IT>报表部分,38 页. 公用的报表方法 修改报表时, 要么覆写现有的报表方法, 要么新增自己的方法, 并通过其它方法来调用。 下面是运行报表时方法的执行顺序:

init() ? dialog() ? run() ? fetch() ? send() ? print() 1. Init()和 dialog()在装载报表时触发。 2. Run()在点击对话框的 OK 按钮时触发。 3. Fetch()用来循环 Query 里的每一条记录, 当找到记录后触发 Send()方法, 并把数据送到报表设计(Report Design) ,注意,如果覆写了 Fetch 方法,我们需要手工调用 Send 方法来发送数据到报表。 4. 最后触发 print()。 这些方法是报表中非常重要的方法,也是我们最常覆写的方法。常用的客户化方法主要 有:在对话框中增加控件,在打印之前处理从 Query 查询出来的数据,和通过执行 programmable section 来调整报表的输出。 上述所列的方法调用顺序仅对报表运行构架(report Runbase framework)有效的情况起 作用,倘若我们直接从 AOT 执行报表而不是通过菜单的话,方法的调用顺序稍有改变,如 下所示: init() ? run() ? prompt() ? fetch() ? send() ? print() 请注意, dialog()不再被触发。 此时 RunBaseReportStd 控制了报表对话框, 当报表 Runbase 构架(Runbase framework)无效时才调用 Prompt()方法。

35、获得当前用户的相关信息
static void GetUserInfo(Args _args) { UserInfo UserInfo ; ; Print infolog.isoCurrencyCode(); // 货币种类 Print infolog.Language(); pause; } // 当前语言

36、两个表之间建立 Query
static void Exercise3(Args _args) { CustTable _custTable; CustTrans _custTrans; Query q = new Query(); QueryBuildDataSource qbdCustTable; QueryBuildDataSource qbdCustTrans; QueryRun _queryExercise; Name _name; AmountMST _amountMST; ; //add the first data source. qbdCustTable = q.addDataSource(TableNum(CustTable)); qbdCustTable.addSortField(FieldNum(CustTable,Name)); //add the second datasource. qbdCustTrans = qbdCustTable.addDataSource(TableNum(CustTrans)); //declare the relation between the two datasources. qbdCustTrans.joinMode(JoinMode::InnerJoin); qbdCustTrans.addLink(fieldnum(CustTable,AccountNum), fieldnum(CustTrans,AccountNum)); _queryExercise = new QueryRun(q); if (_queryExercise.prompt()) { //the query is sorted by Customer.

while (_queryExercise.next()) { _custTable = _queryExercise.getNo(1); _custTrans = _queryExercise.getNo(2); if (_name != _custTable.Name) { print _custTable.Name+" "+ num2str(_amountMST,10,2,2,1); //start calculating for the next customer. _name = _custTable.Name; _amountMST = 0; } //increase the total amout of sales orders _amountMST += _custTrans.AmountMST; } } pause; }

37、临时表的应用
我想用临时表作一个缓冲存储,然后用报表打印里面的数据。但是临时表的数据好像不 是那么容易得到,请高手指点下怎么做, 才能在 FORM 里面调用报表打印。临时表的数据也是通过 form 创建的。 谢谢了。 --------------------------------------------------------------------------------------------------------------我也在苦闷中,不知道临时表的生命周期是怎样的! 我写了个 Query,把正式表的数据用 RecordInsertList 拷到临时表中,结果总查不出来,但是 把临时表改为非临时表时,结果又可以查出来! ----------------------------------------------------------------------------------------------------------------临时表数据存贮在数据源中 ----------------------------------------------------------------------------------------------------------------临时表尤如变量, 离开它的 SCOPE 就无效了. 注意临时表的这个方法 public final void setTmpData(Common _cursor) 比如 TmpTalbe tmp1, tmp2; tmp2.setTmpData(tmp1);

结果 tmp1 和 tmp2 拥有相同的 data. 怎么做,才能在 FORM 里面调用报表打印。临时表的数据也是通过 form 创建的。 answer: 用上面的临时表方法在 Report 中接受 Form 中传过来的 data.. ----------------------------------------------------------------------------------------------------------------根据临时表的不同声明方式有不同的传递数据的方法: 如果用 TMP* 来声明,一般来说用循环结构来 Insert 值。 如果声明的是一个表的变量,那么一般用 setTmpData() 传递数据。 这两种不同的声明方式,第一种方式是声明一个临时表,第二种方式是将一个表变量临 时化。 ----------------------------------------------------------------------------------------------------------------临时表如果作 Report 的 Data Source 必须用下面方法来得到数据 QueryRun.setRecord(临时表实例);

38、判断某个用户是否属于某个组
1,函数 public static boolean isIncludesInUserGroup(userID _userid,userGroupID _UserGroup) { userGroupList userGroupList; boolean ret; ; select firstonly groupId from userGroupList where userGroupList.userId userGrouplist.groupId==_userGroup; if (userGroupList.userId!='') ret=true; else ret=false; return ret; } 2,解释:判断某个用户(_UserID)是否属于某个用户组(_UserGroup); 3,_userID,传入需要判断的用户 ID,_UserGroup,转入用户组; 4,Job 调用演示: print clsglobe::IncludesInUserGroup('B01','Admin');pause;

==

_userID

&&

输出: TRUE

// 这个更简单 if(UserInfoHelp::userInUserGroup(curuserid(),'Admin') ) { info("Yes"); }

39、强制同步表
解决如下编译错误: Cannot execute a data definition language command on (). The SQL database has issued an error., static void forceDbSynchronize(Args _args) { Dictionary dict; int idx, lastIdx, totalTables; TableId tableId; Application application; SysOperationProgress progress; StackBase errorStack; ErrorTxt errorTxt; ; application = new Application(); dict = new Dictionary(); totalTables = dict.tableCnt(); progress = new SysOperationProgress(); progress.setTotal(totalTables); progress.setCaption("@SYS90206"); errorStack = new StackBase(Types::String); lastIdx = 0; try { for (idx = lastIdx+1; idx <= totalTables; idx++) { tableId = dict.tableCnt2Id(idx); progress.setText(dict.tableName(tableId)); lastIdx = idx; application.dbSynchronize(tableId, false, true, false);

progress.incCount(); } } catch (Exception::Error) { errorTxt = strFmt("Error in table '%1' (%2)", tableId, dict.tableName(tableId)); errorStack.push(errorTxt); retry; } setPrefix("@SYS86407"); errorTxt = errorStack.pop(); while (errorTxt) { error(errorTxt); errorTxt = errorStack.pop(); } }

40、清除数据库缓存
在查询窗口中执行: CHECKPOINT DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS DBCC FREEPROCCACHE WITH NO_INFOMSGS

41、取得当前窗体 Data Source 的表名?
void clicked() { int i; formdataSource fds; ; super(); for (i=1;i<=element.dataSourceCount();i++) { fds = element.objectSet(i) ; info(tableId2name( fds.table())); }

}

42、如何把 Form 上显示的值传到 report 中打印?
把你要打印的字段放到表的 field Groups | autoreport 下, 然后在 form 的打印预览即可。

43、如何遍历报表
static void Job7(Args _args) { #AOT str Reportname,ReportLabel,s; TreeNode tmp,node,design; TreeNodeIterator iterator; int i; ReportList tl; ; delete_from tl; select firstonly tl ; node = infolog.findNode(#ReportsPath); if (node) { iterator = node.AOTiterator(); if (iterator) tmp = iterator.next(); while (tmp) { Reportname = tmp.treeNodeName(); design = tmp.AOTfindChild( 'Designs');

if (design) { design = design.AOTfirstChild(); if (design) {

s = design.AOTgetProperty('caption'); ReportLabel = syslabel::labelId2String(s); } } if (ReportLabel) { tl.ReportName = reportname; tl.ReportLabel = ReportLabel; tl.insert(); } tmp = iterator.next(); } } pause; }

44、如何改小数位
在报表里面吗?可以设置报表字段的 NoOfDecimals 来实现.但最好修改 extenddatatype 的 NoOfDecimals 的 位 数 , 这 样 , 所 有 用 到 改 扩 展 类 型 的 地 方 都 会 更 着 改 , 包 括 form,editer,gride,report 等. 1 在 AOT 中找出你要改字段的是那个表的哪个字段, 然后在 AOT ->DATA DICTIONARY-> TABLE 中找到该表的和字段,在字段属性上,有 EXTENDEDDATATYPE 这个属性,该属性定义 了你字段的类型。 然后在 AOT ->DATA DICTIONARY-> EXTENDED DATA TYPE 中找到该扩展类型, 右键属性就可看到 NoOfDecimal ,有问题再上来问了? 2 看你单价该字段的数据类型,如果是和数量和总金额是同一个扩展类型的话,就会 改为 2 位。

45、如何取得 AX 的安装路径?
用 xInfo::directory(DirectoryType::Appl)可以根据 DirectoryType 的类型取得各种路径. // 取得客户端 BIN 文件路径并创建一个临时 Temp 文件夹 filePath = xInfo::directory(DirectoryType::Bin) + "\Temp"; if(!WinApi::folderExists(filePath)) {

if(!WinApi::createDirectory(filePath)) { info("创建目录失败!"); return; } } static void Job7(Args _args) { xtTPBtmpInventTable it; it.setTmp(); it.ItemId = xinfo::releaseVersion(); it.ItemAllName = xinfo::buildNo(); it.ItemGroupId = xinfo::productName(); it.insert(); info(it.ItemId+" } "+it.ItemAllName +" "+it.ItemGroupId);

46、如何用代码清除 query 中所下的过滤条件?
static void CusttomClearRanges(QueryBuildDataSource qbds) { int i; QueryBuildDataSource qbdsInternal; ; qbds.clearRanges(); for(i=1;i<=qbds.childDataSourceCount();i++) { qbdsInternal = qbds.childDataSourceNo(i); Ranges::CusttomClearRanges(qbdsInternal); } } 测试用例 static void TestExample(Args _args)

{ ProdTable InventTable InventItemLocation QueryBuildDataSource QueryBuildDataSource QueryBuildDataSource QueryBuildDataSource prodTable; inventTable; inventItemLocation; qbdsProdTable; qbdsInventTable; qbdsInventDim; qbdsInventItemLocation;

Query query; ; query = new Query(); qbdsProdTable = query.addDataSource(tableNum(ProdTable)); qbdsInventTable = qbdsProdTable.addDataSource(tableNum(InventTable)); qbdsInventItemLocation qbdsInventTable.addDataSource(tableNum(InventItemLocation)); qbdsInventDim = qbdsProdTable.addDataSource(tableNum(InventDim)); qbdsInventTable.relations(true); qbdsInventDim.relations(true); qbdsInventItemLocation.relations(true); qbdsInventTable.fetchMode(0); qbdsInventDim.fetchMode(0); qbdsProdTable.addRange(fieldNum(ProdTable,prodId)).value('aa'); qbdsInventTable.addRange(fieldNum(InventTable,itemId)).value('bb'); qbdsInventItemLocation.addRange(fieldNum(InventItemLocation,itemId)).value('cc'); qbdsInventDim.addRange(fieldNum(InventDim,inventDimId)).value('dd'); //清除过滤条件前 info(qbdsProdTable.toString()); Ranges::CusttomClearRanges(query.dataSourceTable(tableNum(ProdTable))); //清除过滤条件后 info(qbdsProdTable.toString()); }

=

47、如何在一个窗体中关闭另一个窗体
参考如下方式 1.重载 B 窗体的 init 方法,添加类似于如下的代码: public void init() { super(); infolog.globalCache().set("B","FormB",element); } 2.重载 B 窗体的 close 方法 public void close() { super(); infolog.globalCache().remove("B","FormB"); } 上述代码是将指向 B 窗体的引用保存到全局缓存中, 并在 B 窗体关闭的时候从全局缓存 中去除掉 B 窗体的引用。 3.重载 A 窗体按钮的 clicked 方法: void clicked() { FormRun fr; ; super(); if(infolog.globalCache().get('B','FormB')) { fr = infolog.globalCache().get('B','FormB'); fr.close(); } } 当然上面这段代码只能关闭最后一个打开的 B 窗体,如果要关闭所有打开过的 B 窗体, 改一下上述代码就可以了。

48、实现定时关闭 Form
在 From 中编辑以下代码: // getdata 方法是实现关闭 Form,cmdOK 是一个关闭按钮.

public void getData() { cmdok.clicked();//同 this.close(),方法功能一样; }

//在运行时设置溢出时间为 1000 秒 public void run() { super(); this.setTimeOut('getdata',1000,true); }

49、实现动态跳转
void clicked() { Args MenuFunction ;

parameters = new Args(); salesConfirmMenu;

if(xtTPBDataTransact.ItemRelease == 1) { salesConfirmMenu = new MenuFunction(menuItemdisplayStr(xtMPBDataTransform_Invent), MenuItemType::display); } if(xtTPBDataTransact.RouteRelease == 1) { salesConfirmMenu = new MenuFunction(menuItemdisplayStr(xtMPBDataTransform_Route), MenuItemType::display); } if(xtTPBDataTransact.EbomRelease == 1 || xtTPBDataTransact.MbomRelease == 1) { salesConfirmMenu = new MenuFunction(menuItemOutPutStr(xtMPBDataTransform_Bom), MenuItemType::Output); } parameters.caller(this);

parameters.record(xtTPBDataTransact);

salesConfirmMenu.run(parameters); }

50、使用 X++建一个 Project
static void Job1(Args _args) { ProjectNode pNode; ProjectGroupNode pgNode; ProjectListNode plNode; ; //delete project pNode = SysTreeNode::getPrivateProject().AOTfindChild("testPrivateProject"); if(pNode) pNode.AOTdelete(); //create test project pNode = SysTreeNode::getPrivateProject().AOTadd("testPrivateProject"); //load project pNode = pNode.getRunNode(); //add group node to project pgNode = pNode.AOTadd("testGroup"); pgNode.projectGroupType(GroupNodeType::Tables); //add node to group pgNode.addNode(TreeNode::findNode("\\Classes").AOTfirstChild()); //add node to project pNode.addNode(TreeNode::findNode("\\Forms").AOTfirstChild()); //save project pNode.AOTsave(); }

51、在 AX 中实现 Not like 的三种常用方法
没有直接的 not like,但是可以通过变换。 通过举例,选择出 PurchTable 中不是 00007 开头的 purchId 的第一条记录

三种办法,第一种,也是最简单的就是 PurchTable purchTable; ; select firstonly purchTable where !(purchTable.purchId like '00007*'); 第二种方法 PurchTable purchTable, refPurchTable; ; select firstonly purchTable notexists join refPurchTable where purchTable.PurchId like '00007*'; 第三种方法,采用 Query Query query = new Query(); QueryRun queryRun; ; query.addDataSource(tableNum(PurchTable)).addRange(fieldNum(PurchTable, PurchId)).value('!00007*'); queryRun = new QueryRun(query); if(queryRun.next()) { purchTable = queryRun.get(tableNum(PurchTable)); print purchTable.PurchId; pause; }

52、怎样在下拉框中显示有过滤条件的数据
比如要在下拉框中显示 ItemID,但是只显示 ItemGroup='Group1' 且 ItemType='Bom'的物 项 ,那 么传统 的使 用扩展 类型 的方法 就不使 用了 ,因 为扩展 类型不 能动 态传 递参数 (Itemgroup 和 ITEMTYPE) 。 方法 1, 在 InventTable 里建立一个方法,lookupItemByItemTypeGroup, client static void lookupItemByItemTypeGroup(FormStringControl lookupCtrl, ItemGroupId ItemGroupId,ItemType _ItemTYpe=ItemType::BOM) { SysTableLookup sysTableLookup = SysTableLookup::newParameters(tableNum(InventTable), lookupCtrl); Query query = new Query();

QueryBuildDataSource queryBuildDataSource query.addDataSource(tableNum(InventTable)); QueryBuildRange queryBuildRange queryBuildDataSource.addRange(fieldNum(InventTable, ItemGroupId)); QueryBuildRange queryBuildRange1 queryBuildDataSource.addRange(fieldNum(InventTable, ItemType)); ; QueryBuildRange.value(ItemGroupId); QueryBuildRange1.value(enum2str(_ItemTYpe)); sysTableLookup.addLookupfield(fieldNum(InventTable, ItemId)); sysTableLookup.addLookupfield(fieldNum(InventTable, ItemName)); sysTableLookup.parmQuery(query); sysTableLookup.performFormLookup(); } 第二步,重载下拉框的 lookup 的方法。 public void lookup() {

= = =

// super();//注意,一定要注释,意思是不执行父类的方法而执行当前类的方法,若 不注释则出现两个下拉框。 ; inventtable::lookupItemByItemTypeGroup(this,'Group1',ItemType::BOM); } 方法 2,就是直接在控件的 lookup 方法下写上面的代码,这样就没有扩展性,但是有的 时候还是可以选择。 当下拉框需要从多个表过滤条件时,上面的方法就不起作用了。这个时候,我们需要建 立一个 View,然后把 view 当作表使用上面的方法,就可以实现了。 比如我们要在下拉框中选择工单,条件是 ITemGroupID 是"Group1"的物项,这样就需要 关联两个表,过滤 Inventtable 的 ItemGroupID. 若有问题可以提问,我再回答,但是,只要自己思考一下的话,一般不是问题。

整理:pangningwxh 2009 年 12 月 10 日



推荐相关:
网站首页 | 网站地图
All rights reserved Powered by 学霸学习网 www.tceic.com
copyright ©right 2010-2021。
文档资料库内容来自网络,如有侵犯请联系客服。zhit325@126.com