4.Treelist、Freeform组件


问1.demo页中,有的数据用XML格式、有的用JSON、有的是TXT,有规定吗?

没规定。
  硕正套件是自适应的,即能够自动识别数据的格式。

问2.模板中的列,和加载的数据XML中的列,要严格对应吗?

是按照列名映射的,但双方的排列顺序、列的数量不一定要严格对齐,比如你的模板中有10列,数据XML可以有15列、也可以只有5列。多出来的数据,我们会自动抛弃、不足的列,内容当然就是空。

问3.我明明删除了1行数据,调用GetChangedXML()却返回空串(即内容未被修改过),这是为什么?

您必须在 <Properties> 中定义Key属性,指定主键。

问4.Treelist的XML规范有点复杂,我需要去啃它吗?

是的,这是必需的,因为Treelist目前还没有象Supcan Report那样的所见所得设计工具。该XML规范其实也并不复杂,您可以随时查阅帮助文档,常用的元素不会超过20个。

问5.某列采用了下拉Treelist,下拉选择后,如何取得选中内容、和下拉Treelist中选中行各列的内容?

如果仅仅是取单元格的显示内容,调用GetCellText( )函数就行,该函数取得的是显示内容,而非数据。
  如果需要取下拉选中行的其它列的内容,可以用 GetDropCellData 函数直接取得,请参见演示页 “29.下拉的其它功能” 中的演示。
  GetDropCellData 为 1.0.89.0 版的新增函数,如果您用的是以前的版本,必须先调用GetHandle( )函数取得下拉Treelist的句柄,然后调用扩展函数的GetCurrentRow( )取得下拉Treelist的当前行,最后调用扩展函数GetCellData()即可。


问6.我采用Freeform、Treelist分别作为表单的表头、表体,但打印时只能打出表体部分,如何才能按照我自己的格式打印完整的表单呢?

最完美的方案是:同时引入硕正 Report 组件,并且应预先准备好一张使用了临时数据源的报表。
  关于数据的传递,可以先执行 Freeform 和 Treelist 的 Export 函数取得XML串,然后通过 Report 的 SetSource( ) 函数,将这XML大串传入。 在 “在线演示” \ “自由表头” 下有完整的例子:“9.有表头表体的表单(2)”,这种方案最大的好处是,报表格式可以自由设计,并为实施人员、甚至最终用户自行更改输出格式扫平了道路。
  另外还有一个偷懒的简化方案:使用 <Properties> \ <PrintPages> 配置, 用程序动态更改各个 Layer 的内容,具体请参考《Treelist XML文档规范》。

问7.调用GetChangedXML( "level=0" )取得XML串,发现如果内容未改则返回空串,有没有简单的方法取得完整串而不管内容是否有改动?

答复: GetChangedXML( "level=0; isIgnoreChange=true" )。

问8.XML模板或API中,有很多处的URL(例如 dataURL)属性,如果采用相对URL,到底相对谁?

遵循这2个规则: 1.谁定义,就相对谁; 2.斜杠("/")开头表示相对根目录。

问9.Treelist的表达式、函数、宏不能完全解决我的客户端逻辑,怎么办?

注意到函数js()了吗?它能反向调用当前页面的js,你可以把复杂的客户端逻辑写到页面Js中。

问10.在Windows7下,为什么有的Treelist的输入处光标不会闪烁?

是因为行高不够,适当调高即可。

问11.设为主键(Key)的字段,如果我没输入或输入重复,用GetChangedXML函数提交时会提示错误。怎样才能不提示? 因为我的主键是后端生成的,客户端根本不需要校验

请参考GetChangedXML( )函数中的 isValidateKey 参数。

问12.可编辑的下拉的列,我能任意输入吗(即内容不在下拉列表中的)?

可以,需要定义 freeInputAble="true"。

问13.最简单的下拉(Droplist),我看到例子中的数据都是静态的:

 <DropList id="country">
    <item key="1">France</item>
    <item key="2">Germany</item>
    <item key="3">Brazil</item>
    <item key="4">Belgium</item>
   </DropList>
  能否动态从数据库取?

  可以,写成例如这样:
    <DropList id="country" dataURL="../service/getcountry.aspx" />
  这个aspx返回的数据格式比较自由,也可以和静态数据的一样。比如:
<?xml version="1.0" encoding="utf-8"?>
<data>
 <item key="1">France</item>
 <item key="2">Germany</item>
 <item key="3">Brazil</item>
</data>
  也可以是类似这样:
<?xml version="1.0" encoding="utf-8"?>
<data>
 <record>
  <key>1</key>
  <value>France</value>
 </record>
 <record>
  <key>2</key>
  <value>Germany</value>
 </record>
 <record>
  <key>3</key>
  <value>Brazil</value>
 </record>
</data>

问14.我的计算表达式是这样写的:     <express> price=if(amount >= 1000, 2.3, 3.0) </express> 为什么结果不正确?

在元素 <name> ... </name> 之间的串中,大于、小于符号请务必将写成 &gt;&lt;, 或者用 <![CData[  ]]>包绕。

问15.计算表达式中,里面的变量只能是列名,但我有一个表达式是需要从外部取数的,怎样实现?

有几个方案您可以参考:
1.树列表增加一个不可视的列,将“外部数据”置到这一列中 (可以用 SetColCellData 函数);
2.表达式中采用 js( ) 反向调用函数;


问16.服务器搜索以例“10.可编辑的下拉”中的“经销商”为例,假设我们希望弹出的经销商下拉和“订单号”有关,如何实现?

您可以在事件中动态修改下拉的 dataURL。例如:
var curRow = -1;
function OnEvent(id, Event, p1, p2, p3, p4)
{
 if(id=='AF' && Event=='SelChanged') {
  if(p1 != curRow) {  //当前行有切换
   curRow = p1;
   var orderId = AF.func("GetCellData", curRow + "\r\n orderId");
   AF.func('SetDropListProp', "customer2 \r\n dataURL \r\n='/myapp/data.aspx?orderId=" +orderId+ "&substr='+encodeURIComponent(data)");
  }
  return;
 }
 ... 
打开 httplog 跟踪一下请求,您能看到:
不同的行,下拉确实不一样了。


问17. 怎样导出分页显示中的全部数据?

不管是打印全部数据、还是导出全部数据,首先必须要让树列表加载全部数据。有如下3种方案您可以尝试:
1.方案1
  在Freeform的 Pager 分页器中,找到 PageRowsList 属性,在属性的值中增加一项, 比如 "全部数据(100000行)",这样用户自己就能按需导出;
2.方案2
  执行 EnableMenu 函数,注意函数文档中的“exportAll”参数,使得右键菜单中能弹出“转换输出全部页”;
  该菜单项会触发 RequestAllPages 事件,请在该事件中加载全部数据即可。
3.方案3
  在外部菜单中通过调用Treelist的函数实现,调用的函数无非就是 Load、OpenExportDialog.
  为了不影响原Treelist的显示,您也可以在页面的可视区域安置一个2px X 2px的Treelist,用这个Treelist来加载数据、转换输出。
  如果数据行数很多,为了及时释放客户端内存,可以在导出后将数据行删除,或执行一遍Build也能起到清理内存的作用。


问18.执行如下的代码,感觉明显有个合并的过程:

 AF.func("Build", supcanTitle);
 AF.func("Load", dataXML);
 AF.func("mergeSame", "col=compute_rule");
  怎样消除这个现象?

  增加 SetRedrawAble 函数试试,比如:
 AF.func("Build", supcanTitle);
 AF.func("SetRedrawAble", "false");   //关闭重画
 AF.func("Load", dataXML);
 AF.func("mergeSame", "col=compute_rule");
 AF.func("SetRedrawAble", "true");   //开启重画

  如果还有合并痕迹,在Load函数增加 "FadeInStep=0" 参数再试试:
 ...
 AF.func("Load", dataXML + "\r\n FadeInStep=0");
 ...


问19.我采用分页显示,并使用了合计行,如何才能使合计结果是全部数据的合计,而不是当前分页的合计?

首先,页面应该得到总的合计数,然后,用 SetColProp 动态修改树列表某列的 TotalExpress 表达式,将结果赋予给它,例如:
AF.func("SetColProp", "prodPrc \r\n totalExpress \r\n='312,440,221.33'");
  请注意其中的表达式书写规则,如果您直接写成了AF.func("SetColProp", "prodPrc \r\n totalExpress \r\n=312440221.33"), 显示出来可能没有千位符的。


问20.在例子 “28.过滤: 关联下拉” 中,我想达到这个效果:省份中增加一 “全国”,希望在选择它后,右侧的“城市”列能列出所有城市,怎么实现?

假如“全国”的 id 为 "0", 将过滤表达式修改为:
var exp = "provId@parent=provinceId || if(provId@parent=='0', 1, 0) \r\n cityId";
AF1.func("Filter", exp);
  请仔细揣摩一下。


问21.上一例,省份可以多选的,这个我已经实现,但我想达到这个效果:希望在多选后,右侧的“城市”列能列出这些省的所有城市,怎么实现?

您可以这样写:
var exp = "indexOfArray(provId@parent, provinceId)>=0 \r\n cityId";
AF1.func("Filter", exp);
  如果您的版本尚不支持 indexOfArray 计算函数,并且假设省份id的宽度都一致,那么请这样写:
var exp = "indexOf(provId@parent, provinceId)>=0 \r\n cityId";
AF1.func("Filter", exp);

问22.我在Freeform中采用了 EditWithButton (带按钮输入控件),按下按钮后弹出硕正的模式对话框,希望对话框关闭后能跳转到“prince”输入框,但发现用 SelectCell 不起作用,怎样才能让它起作用?

我们发现是有问题,在对话框关闭后焦点无法定位,可能和底层消息机制有关。但有个简单的方法可以解决:调用全局函数 PostMessage, 即在消息队列的尾部添加一个自定义事件,您就在该事件中去处理焦点函数吧,例如:
function OnEvent(id, Event, p1, p2, p3, p4)
{
 if(Event == "ButtonClicked" && p1 == "product") {
  AF.func("OpenDialog", "...(略)");  //打开模式对话框
  AF.func("PostMessage", "p1=kk1");  //发送自定义事件
 }
 else if(Event=="UserEvent" && p1=="kk1") {
  //响应该事件
  AF.func("SelectCell", "price");
 }
}

问23.我想做这样一个关联下拉功能,以 freeform 的例子 “3.多种下拉” 为例, 在 “客户” 处选择后,希望 “经销商” 的动态下拉,能自动把选中的 “客户” 也作为查询条件带给后端的请求中:

相当于是动态修改 “经销商” 下拉的 dataURL,请将如下脚本加到 f3.htm 页面中,试一下:
function OnEvent(id, Event, p1, p2, p3, p4)
{
 if(id == 'AF1' && Event=='DropdownSelChanged') {
  var cust = AF1.func("GetValue", "cust");
  var url = "='http://www.supcan.cn/dotnet/customer.aspx?cust=" +cust+ "&substr='+encodeURIComponent(data)";
  AF1.func("SetDroplistProp", "sales \r\n dataURL \r\n" + url);
 }
}

问24.怎么获得树列表的合计/小计内容?

就用 GetCellData 函数,当然,您须先用 isTotalRow / isSubTotalRow 判断该行是否合计/小计行。


问25.怎样彻底抛弃树列表中的数据? 即回到 Build 后的状态

Load空串即可, 或者执行一下 Build 重新创建也可以。


问26.我需要三级的下拉,比如 t1.xml 的 A 列是引用下拉树列表 t2.xml,而 t2.xml 中的 B 列又需要引用 t3.xml,发现t3.xml的数据不能自动加载, 怎么解决?

修改 t2.xml, 在<Properties>中增加 DropDataLoadMode="synch" ,即让它同步加载。


问27.我在 Freeform 中使用了 <WebBrowser>, 即嵌入一个浏览器页面,我该怎样与这个页面做数据交互呢?

如果这个页面中也含有硕正插件,可以调用全局函数中的缓存函数 SaveCache/ReadCache 去存取。
  如果此页面本身是个纯页面,那只能通过服务器去绕了,比如暂时缓存到 Session。