摘要: 禁止同一用户多次登录void startupPost() { int counter; int maxUserSessions = 1; int maxAdminSessions = 4; int num = 0; int maxSessions = Info::licensedUsersTotal(); xSession session; UserInfo userInfo; UserId currentUserId; UserGroupList UserGroupList; FormRun formRun; ; currentUserId = curuserid(); if (curren 阅读全文
posted @ 2012-04-10 17:22 K小子 阅读(366) 评论(0) 推荐(0)
摘要: void CleanMap(map _map){ MapEnumerator mapEnumerator; ; mapEnumerator = _map.getEnumerator(); while (mapEnumerator.moveNext()) { if (_map.exists(mapEnumerator.currentKey())) _map.remove(mapEnumerator.currentKey()); } return; } 阅读全文
posted @ 2012-04-10 17:12 K小子 阅读(218) 评论(0) 推荐(0)
摘要: 【项目实施随笔】打扮一下生产订单前面提到给生产BOM增加一个状态,表示各个部门的修改状态,今天用户又提出,想看到五颜六色的生产订单,生产BOM在不同的修改阶段用不同的颜色表示,人还是对颜色这东西比较敏感。AX的优势在于快速开发,对于一些不用太多时间就可以搞定的东西,与其费力气去劝说用户,还不如花一两分钟时间实现他们的需求,然后让他们自己去衡量利弊,当他们自己意识到原来自己想象中的效果实现后还不如之前的时候,他们就会欣然接受你的主意。1.窗体ProdTable数据源ProdTable的displayOption方法: Codepublic void displayOptio... 阅读全文
posted @ 2012-04-10 12:08 K小子 阅读(160) 评论(0) 推荐(0)
摘要: 读取Info内容后记:最近发现其实AX里的类Info已经提供了相应的静态方法infoCon2Str来实现这个功能,所以可以直接调用这个方法去实现本文所说的功能,本文不看也罢。AX用Infolog去管理用户操作中的出错或者提示信息,最后用SysInfologBrowser这个窗体去展现,但如果通过.NET Business Connector之类的去调用AX的系统类就不可能用这种方法了,因为不可能将窗体通过.NET Business Connector去展现,如果想知道调用的系统类到底发生了什么事情,可以把Infolog的内容转换成字符串返回给调用者。窗体SysInfologBrowser的数据 阅读全文
posted @ 2012-04-10 12:03 K小子 阅读(332) 评论(0) 推荐(0)
摘要: 实现Pick和ReigisterAX有个问题是很多功能都跟表现层窗体绑定在一起,要用代码直接实现某个功能就需要看窗体中的代码是如何处理的并将其剥离出来。比如领料和登记功能,它都封装到了窗体InventTransPick和InventTransRegister中,虽然也是通过类InventTransWMS,InventTransWMS_Pick和InventTransWMS_Register实现相应的功能,但如果要通过代码直接实现Pick和Register功能就需要看一下它们的处理逻辑,并将其改造一下。1.给InventTransWMS_Pick和InventTransWMS_Register分 阅读全文
posted @ 2012-04-10 12:02 K小子 阅读(455) 评论(0) 推荐(0)
摘要: 修改Project中的表名及字段名 开发了大半,遇到这样一个需求:1.自己创建的表,要加上公司的简称做为前缀;2.自己创建的表的字段不需要添加公司的简称做为前缀;3.在系统原有的表上添加的字段要添加公司的简称做为前缀。创建的表太多了,一个个修改是重体力活,于是写了个Job来完成,在这里记录一下: static void ModifyTableAndFieldNameOfSomeProject(Args _args) { #TreeNodeSysNodeType #define.prefix('PF') #define.ProjectName('ProjectName&# 阅读全文
posted @ 2012-04-10 12:00 K小子 阅读(630) 评论(0) 推荐(0)
摘要: 用代码修改类名新创建一个类TestClass,用代码修改其类名为NewTestClass: static void ChangeClassName(Args _args) { #AOT TreeNode treeNode = TreeNode::findNode(#ClassesPath+'\\TestClass'); ; treeNode.AOTsetProperty("Name","NewTestClass"); treeNode.AOTcompile(1); treeNode.AOTsave(); }在运行到treeNode.AOT 阅读全文
posted @ 2012-04-10 11:58 K小子 阅读(228) 评论(0) 推荐(0)
摘要: 创建采购订单 经常要用代码创建采购和销售订单,需要弄清楚哪些字段是必输的,这段代码经常需要拷贝,放在这里做个备份。 static void CreatePurchDirectly(Args _args) { PurchTable purchTable; PurchLine purchLine; InventDim inventDim; ; ttsbegin; //PurchTable //PurchId purchTable.PurchId = NumberSeq::newGetNum(PurchParameters::numRefPurchId()).num();pur... 阅读全文
posted @ 2012-04-10 11:58 K小子 阅读(398) 评论(0) 推荐(0)
摘要: static void axd_importinventtable_excel(Args _args){sysexcelapplication m_application;sysexcelworkbooks m_workbooks;sysexcelworkbook m_workbook;sysexcelworksheets m_worksheets;sysexcelworksheet m_worksheet;sysexcelcells m_cells;//enum typeItemType m_ItemType;NoYes m_NoYes;SalesPriceModel m_SalesPric 阅读全文
posted @ 2012-04-10 11:56 K小子 阅读(399) 评论(0) 推荐(0)
摘要: 定时调用某个方法在Form中可以调用FormRun的setTimeOut方法,实现定时调用某个方法,但如何是一般的类,不是窗体,该如何实现那?1.在全局缓存中缓存当前对象. server static void Main(Args _args) { TestClass testClass = new TestClass(); SysGlobalCache cache = infolog.globalCache(); ; cache.set(classstr(TestClass),"HelloTestClass",testClass); testClass.testMeth. 阅读全文
posted @ 2012-04-10 11:55 K小子 阅读(311) 评论(0) 推荐(0)
摘要: 用X++代码创建表 用代码创建表的代码,在这里记录一下: static void CreateNewTable(Args _args) { #AOT TreeNode treeNode = TreeNode::findNode(#TablesPath); DictType dictType; TreeNode treeNodeField; str tableName = 'Student'; str fieldName1 = 'StudentNum'; str fieldName2 = 'StudentName'; AOTTableFieldLi 阅读全文
posted @ 2012-04-10 11:54 K小子 阅读(185) 评论(0) 推荐(0)
摘要: 将 转移单 自动发货说到开发,首先想到的是对语言语法细节的熟悉,对面向对象的理解.对于AX的二次开发,这些当然也比较重要,但相对来说更加重要的是对系统已有的几千张表和几千个类的熟悉.决定二次开发速度的主要因素也是对这些表和类的理解,因为系统中有大量的功能已经封装成了比较好的类可以调用,比如获取库存的现有量想到InventOnhand可以使用,想获取此前某一天的库存量可以用InventSumDate,销售订单和采购订单的过账可以调用SaelsFormLetter和PurchFormLetter的update方法等等.有些公司一些移库,采购销售的动作并不想通过人为操作过账,而是想让系统自己完成,这 阅读全文
posted @ 2012-04-10 11:52 K小子 阅读(338) 评论(0) 推荐(0)
摘要: TypeId浅析AX提供了一些内置函数用来获取数据的类型,比如Typeof(),比如ClassIdGet(),TypeId().这里只讨论一下TypeId(),查了半天都没找到关于这个函数的描述,倒是Inside AX这本书对TypeOf()有所描述:Typeof()这个系统函数以变量实例为入参,返回入参对应的基本类型,比如下面的例子: int i = 123; str s = "Hello world"; MyClass c; Guid g = newGuid(); print typeOf(i); //Prints Integer print typeOf(s); .. 阅读全文
posted @ 2012-04-10 11:50 K小子 阅读(434) 评论(0) 推荐(0)
摘要: 标签颜色的设定有时候对一些字段的标签要用不同的颜色设定,AX的控件有个属性LabelForegroundColor可以用来干这事。这个字段可以设定的值取决于另一个属性ColorScheme,该属性有Default,Windows palette和RGB三种,我感觉Default和Windows palette是一样的。可以在代码中对这些属性进行设定,如下代码所示: public void init() { super(); //RGB CustTable_AccountNum.colorScheme(FormColorScheme::RGB); CustTable_Ac... 阅读全文
posted @ 2012-04-10 11:48 K小子 阅读(164) 评论(0) 推荐(0)
摘要: 获取最根级EDT类型名称 有时候需要修改某个扩展数据类型的属性,比如字段的长度等,这些属性只能在最根级的EDT类型上修改,所以需要找到最根级的EDT类型,这个小例子演示了如何根据当前表的字段获取其对应的最根级EDT类型。 //Return the top extendtypeid,If error,return '' static ExtendedDataTypeName GetFinalExtendedType(TableId _tableId,FieldId _fieldId) { SysDictField dictField; SysDictType dictTyp... 阅读全文
posted @ 2012-04-10 11:47 K小子 阅读(153) 评论(0) 推荐(0)
摘要: 设定Excel列的格式MBSCN网友Jedison提了一个关于设定Excel列格式的问题,俺写了个例子贴到了MBSCN上,在这里再贴一下,便于以后查找。 static void StyleTest(Args _args) { #Excel #define.AlignModeText('Align_Text') #define.AlignModeNumber('Align_Number') #define.FileName('d:\\StyleTest.xls') #define.Text('@') //文本类型 #define.N 阅读全文
posted @ 2012-04-10 11:46 K小子 阅读(301) 评论(0) 推荐(0)
摘要: 创建自定义的右键菜单有时候用户需要在原有的右键菜单上添加几个选项,有时候需要删掉一些不需要的项,也就是要创建自己的右键菜单。由于右键菜单的实现是由AX核心管理的,我们看不到它的具体实现(至少我没找到实现的代码),我们能做的就是通过控件的showContextMenu来实现自己的想法。本文以CustTable为例,创建一个Form,数据源为CustTable,关注的字段为CustAccount.需求一:去掉右键菜单重载CustAccount的showContextMenu方法即可: public int showContextMenu(int _menuHandle) { ... 阅读全文
posted @ 2012-04-10 11:45 K小子 阅读(270) 评论(0) 推荐(0)
摘要: 人费解窗体数据源之间的关系在Form的数据源之间可以建立各种关系,连接的方式诸如InnerJoin,OuterJoin,Delay之类,可对于两个数据源之间的通过哪些字段进行关联没有显示指定的地方,一直想当然地以为会按照从表上建立的关系去连接,今天让这个问题给郁闷了一把。问题描述改造ProdTable窗体,添加SalesLine做为数据源,目的是将销售订单行的信息显示在生产单上。在ProdTable上添加了一个字段SalesLineRecId,在Form中让ProdTable和SalesLine通过ProdTable的SalesLineRecId和SalesLine的RecId建立InnerJ 阅读全文
posted @ 2012-04-10 11:44 K小子 阅读(714) 评论(0) 推荐(0)
摘要: cacheAddMethod方法display方法会带来效率上的损失,因为每当界面刷新时都会调用display方法,在Inside Dynamics AX在性能(一)这一节介绍了用cacheAddMethod提升性能的做法.FormDataSource的cacheAddMethod可以将display的返回值打包发送到客户端,只有在调用FormDataSource的reread,create和write方法的时候刷新缓存的值.使用这个方法的时候要注意以下两点:1.cacheAddMethod只能缓存定义在表的方法结点上的display方法;2.cacheAddMethod要在FormDataS 阅读全文
posted @ 2012-04-10 11:43 K小子 阅读(278) 评论(0) 推荐(1)
摘要: 给多个表的Dimension字段赋初值[需求]最近遇到这样一个需求,在实施的时候把系统现有的三个纬度前两个分别用于记录分公司和部门,在做财务凭证或者销售采购订单的时候,需要给这些表相应的Dimension字段的前两个纬度赋值,用户要求根据当前用户所属的分公司和部门直接赋值,而不想自己去选择。[分析]最直观的想法就是修改各个表的InitValue()方法,给相应的表赋初值,不过这样的工作量有些大,要修改多个表,并且当需要赋初值的表增加时还需要继续修改相应的表。AX中用Map实现表方法的共享,于是考虑用Map来实现这个功能。只有Map还是不行的因为InitValue()这个方法还是在各个表上的,好 阅读全文
posted @ 2012-04-10 11:41 K小子 阅读(206) 评论(0) 推荐(0)
摘要: 添加图片系统提供了用文档处理为系统中记录添加文档,这样每条记录可以附加一份说明文档,这个功能用起来比较方便,可是有时候遇到的用户比较不够勤劳,他于是希望不点那个工具栏上的图标,直接就可以看到一些东西,比如产品的图片说明。这个时候就需要添加图片。系统是通过window控件来添加图片的,我们有几种方式可以为Widow控件来指定数据来源。 1.直接指定ImageName或者ImageResource属性,其中ImageName只能指定一个物理路径上的文件,ImageResource只能指定AOT上Resource某个节点的ID,其中第一个属性缺乏灵活性,第二个还真没找到办法得到Resources节点 阅读全文
posted @ 2012-04-10 11:39 K小子 阅读(874) 评论(0) 推荐(0)
摘要: 设定Grid行的颜色 有时候需要根据某些单据的值设定不同的颜色,AX中FormDataSource的displayOption方法可是实现这个需求,只要重载一下这个方法即可。 public void displayOption(Common _record, FormRowDisplayOption _options) { SalesTable localSalesTable; ; localSalesTable = _record; _options.fontBold(true); if(localSalesTable.CustAccount == '4000')... 阅读全文
posted @ 2012-04-10 11:38 K小子 阅读(1199) 评论(0) 推荐(0)
摘要: Lookup窗体返回多个值 今天在MBSCN上看到有网友提到一个蛮好的问题,如何用Lookup窗体返回多个值。默认的情况下,AX的Lookup窗体只能返回一个值,赋值给调用Lookup的控件,那么如何返回多个值那?这种情况还是蛮常见的,比如从客户表中选择数据,Lookup窗体中可以显示多个值,比如客户编码,客户名称,客户地址等,如果每次只返回一个值赋值给客户编码,显然不太好,因为用户可能还要同时看到客户名称和客户地址的值。正如那位网友提到的,这个问题要分成两种类型来解决:1.通过调用SysLookupTable类构造的Lookup窗体2.通过直接调用Lookup Form(比如CustTabl 阅读全文
posted @ 2012-04-10 11:37 K小子 阅读(469) 评论(0) 推荐(0)
摘要: Lookup窗体简介 Axapta的Lookup窗体提供了一种通用的供用户选择数据的机制,用户可以很方便地实现数据的选择.比如在创建订单的时候在订单主档可很方便地选择客户,订单明细可以方便地选择物料等. 本文试图解释Lookup窗体的实现方式和原理,大多数内容是Axapta的联机帮助的重新组织,部分内容没有参考资料,属于猜测.准备知识1.控件类型Axapta中的窗体控件根据与数据源的绑定情况可以分为三种,绑定控件,非绑定控件和计算控件.所谓绑定控件是指该控件的DataSource属性指定了某个具体的DataSource,DataField指定了DataSource中的某个字段.非绑定则没有指定 阅读全文
posted @ 2012-04-10 11:36 K小子 阅读(408) 评论(0) 推荐(0)
摘要: 写日志文件 导入数据的时候,数据如果有错,需要写日志文件提醒用户修改数据后再次导入,Axapta提供了TextBuffer这个类用来写txt文件,如下代码所示: static void TextBufferTest(Args _args) { TextBuffer tb; ; tb = new TextBuffer(); tb.insert("Hello World!!",1); tb.toFile(@"C:\TextBufferText.txt"); }当然在4.0下,按照 Write Secure X++ Code中的介绍,由于TextBuffer被 阅读全文
posted @ 2012-04-10 11:33 K小子 阅读(146) 评论(0) 推荐(0)
摘要: 宏的使用 宏带给人的印象坏的远多于好的,即使没有写过程序的人也知道宏病毒,每次打开带有宏的Excel的时候都要提醒你是否要打开,打开可能会染毒的警告.从程序实现的角度讲,Axapta中的宏跟Excel中的宏没什么区别,都是一段可执行代码,或者一个变量的定义,当然打开Axapta的时候不会因为有宏的存在就提醒你要不要打开Axapta,呵呵.另外对于X++的程序员来说,宏带来的也是负面多余正面,因为宏不能精确定义出错的行,写起代码来确实很不方便.但是一个事物存在总有它的道理,所谓存在即合理.宏有什么好处那?我的理解是宏提供了一个集中管理代码的方式,这不正是所谓的OO要达到的封装变化的目的吗?不能用 阅读全文
posted @ 2012-04-10 11:32 K小子 阅读(209) 评论(0) 推荐(0)
摘要: 利用表之间的关系创建Query 我们经常需要根据表之间的关系用代码创建query,SysQuery这个类提供了一个方法queryFromTableRelation,当然这个方法的代码跟我们平常根据表之间的关系构造query的过程是完全一样的,不过它做成了通用的方法,直接调用它就不用自己每次都重复劳动了,另外SysQuery里还有几个不错的方法,值得看一下source.public static Query queryFromTableRelation(Common _parentTable, TableId _relationTableId, boolean _update = false, 阅读全文
posted @ 2012-04-10 10:21 K小子 阅读(246) 评论(0) 推荐(0)
摘要: QueryRun的Reset()方法解释 今天写代码的时候遇到一个问题,在一个过程中用户需要多次输入查询条件,这样同一个QueryRun对象qr需要用到多次,但在第一次prompt后,后面的qr.Next()死活都不执行查询,qr的结果也就不会更新了,翻阅QueryRun的帮助文档,想找到个方法用一下,QueryRun所有的方法中reset方法比较接近俺的想像,鼠标点了下去,鼻子差点气歪,这个函数的解释空空如也,服了.不过试了一下,结果正如自己想像的那样,代码如下: static void qrTest(Args _args) { QueryRun qr; Query q... 阅读全文
posted @ 2012-04-10 10:19 K小子 阅读(185) 评论(0) 推荐(0)
摘要: Map的使用 这里的Map指的是AOT->Data Dictionary->Maps里的map.干吗要弄个Map出来??因为Table不能继承.如果两个表的内容的逻辑基本上是一样的,有必要分别写一套方法吗?显然没必要,这时需要Map,Map说白了就是在一些表中共享的方法库.那么怎么玩那?如何调用某个map中的方法?Common.map::Method();Common是某个表变量,Map是某个map的名称,Method是map中的某个方法.axapta中有很多map使用的例子,比如SalesLine的calcLineDiscExclTax方法就用了map SalesPurchLin 阅读全文
posted @ 2012-04-10 10:17 K小子 阅读(248) 评论(0) 推荐(0)
摘要: 在Axapta中实现split函数在Axapta中没有找到类似于C#中的split函数,在SQL Server中也没有类似的函数,当初写SQL函数的时候用了SQL Server中的系统函数charindex和substr来实现这样的功能,于是首先想到了用函数strFind和subStr来实现split函数.下列代码可以分解一个字符串并打印: static void split(Args _args) { int position; str srcStr; ; srcStr = "AA,BB,CC,"; while(true) { position = strFind(s.. 阅读全文
posted @ 2012-04-10 10:15 K小子 阅读(202) 评论(0) 推荐(0)
摘要: Axapta中的保留字看到一份微软的文档,介绍了Axapta中的保留字,把Axapta中特有的一些保留字和摘录如下:anytype:说明:该类型的方法可以返回任意类型的数据.举例: anytype Method1(Args a) { // Commands Return xyz; }at说明:跟保留字Window结合使用,可以指定输出窗体在Axapta主窗体的相对位置.举例:static void Job4(Args _args) { CustTable ct; window 80,30 at 5,3; while select name from ct { print... 阅读全文
posted @ 2012-04-10 10:13 K小子 阅读(268) 评论(0) 推荐(0)
摘要: pack/unpack runbase Framwork用pack和unpack来保存用户上次操作的值,用户上次操作的值会存在SysLastValue表中,这个功能确实蛮酷,不过今天差点被这个东西给整死,在我机子运行上的好好的代码,弄到客户那边去死活run不起来,Application和DataBase都是一样的,认真地跟踪了一遍代码才知道,原来是由于我开发的机子是两层的,客户的环境是三层造成的,太大意了......两层代码都运行在一个进程中,没有进程间通讯的问题,pack/unpack执行情况:从数据库里取出上次的数据->调用unpack,并用取得的值初始化Dialog,用户看到上次操 阅读全文
posted @ 2012-04-10 10:11 K小子 阅读(885) 评论(0) 推荐(0)
摘要: Agrs Class这个类在很多代码中出现,在启动报表的时候也需要用到它.简单来说这个类用于共享构造参数.在Axapta中之所以可以用Args的方式,是因为:1.通常参数的数目比较少.2.用的参数类型很类似.3.有时候构造一个主要的对象,需要构造与之相关的对象,在构造这些对象时需要用到相同的构造参数.在传统的OO世界里,一个对象往往有多个重载的构造函数,通常情况下这没什么问题,但当一个主要的对象需要通过特定构造器去构造相关的对象时,事情变得糟糕起来.有时候需要通过逻辑判定到底该构造哪个构造函数,并且要在很多层之间传递这些信息.事实证明在Axapta中,很多报表,窗体,Action类的构造参数都 阅读全文
posted @ 2012-04-10 10:09 K小子 阅读(175) 评论(0) 推荐(0)
摘要: QueryBuildRange中的表达式在QueryBuildRange中很容易可以实现这样的功能:查询不同客户编号的客户,比如查询编号为A00001或者A00002的客户。如下代码所示: static void GeneralQueryBuild() { Query q; QueryRun qr; CustTable cust; str queryCriterion; ; q = new Query(); queryCriterion = 'A000001,A000002'; q.addDataSource(tableNum(custtable)).addRange(... 阅读全文
posted @ 2012-04-10 10:08 K小子 阅读(194) 评论(0) 推荐(0)
摘要: X++中的字符串操作函数 每个语言中都会有很方便的操作字符串的函数库,可惜在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 toFindC. 阅读全文
posted @ 2012-04-10 10:06 K小子 阅读(1111) 评论(0) 推荐(0)
摘要: 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 阅读全文
posted @ 2012-04-10 10:05 K小子 阅读(168) 评论(0) 推荐(0)
摘要: 临时表方法:table.setTmp() 将一个表作为临时表使用tmpTable.Data() 一般配合 doinsert()使用,从参数表中Copy一行记录后插入到临时表.tmpTable.SetTmpData(Common cursor) 设置tmpTable中的内容到cursor中 临时表在报表中:将临时表传递给报表做数据源调用SetRecord()方法:this.queryRun().setRecord(tmpTableClass); 临时表在窗体中:在窗体数据源init()方法中写:DataSource1.SetTmpTable(tmpTable); 将临时表作为窗体的数... 阅读全文
posted @ 2012-04-10 10:03 K小子 阅读(324) 评论(0) 推荐(0)
摘要: 使用自定义窗体做为Lookup窗体,其实非常简单:关键地方有两处:CloseSelect方法this.performFormLookup(formRun); 步骤:新建一个窗体作为lookup窗体,将Frame设为Border;添加一个数据源,这个数据源即是lookup内容;覆盖窗体方法CloseSelect写上: (此处我们将Unit表作为Lookup内容) super(unit.unitid); //将unitid用作返回给lookup的值Lookup窗体已完成之后就是在其它Form中调用它:下面贴出窗体中某StringEdit控件的Lookup方法public void lookup() 阅读全文
posted @ 2012-04-10 10:01 K小子 阅读(191) 评论(0) 推荐(0)