基本说明
DataGrid的基本属性和使用方法与Grid一致,本文不再做详细说明,详情请参考:Grid(DCUG)
与Grid最大的不同是:Grid通过items属性定义内部的数据行,而DataGrid通过其所设定的DataSet和DataPath属性所计算得到的EntityList作为自身的数据行。
另外由于DataSet的数据绑定效果,如果我们希望调整DataGrid中的数据,只要直接修改DataSet中的数据,DataSet会自动通知所绑定的DataGrid刷新内部数据行。
详细属性说明
autoCreateColumns
是否自动根据绑定的Entity的DataType自动创建其中的表格列。
如下图虽然我们未在DataGrid中定义与DataType相关的DataColumn:

但是由于设置了autoCreateColumns属性为true,则在运行时,会自动根据关联的Entity对象的DataType创建DataColumn,效果如下:

filterMode
在Grid中我们详细介绍过Grid的过滤栏的功能。如果设置Grid的showFilterBar为true后就可以在Grid中看到过滤栏:

由于Grid中的数据都是定义在items属性中的,因此其过滤工作也是在客户端完成的,也就是说只能对客户端的数据做过滤。
DataGrid通常情况下可能会有分页处理,如果仅仅是客户端的过滤可能并不是客户所需要的功能,在更多的业务场景中用户可能更希望你是一个数据库的查询过滤。
因此DataGrid提供了filterMode属性:

它支持两种过滤查询:clientSide和serverSide。
其中clientSide与Grid的过滤栏查询一样,就是基于Grid中当前可见记录的查询。
如果设置为serverSide查询,那么过滤栏中的查询条件将会被传递到服务器的DataProvider中,由DataProvider处理查询参数Criteria。
参数criteria对应的Java类为:com.bstek.dorado.data.provider.Criteria.java。
@DataProvider
public void getAll(Page<Order> page, Criteria criteria) throws Exception {
if (null!=criteria && criteria.getCriterions().size()>0){
List<Criterion> criterions = criteria.getCriterions();
for(Criterion criterion: criterions){
if (criterion instanceof SingleValueFilterCriterion){
SingleValueFilterCriterion filterCriterion = (SingleValueFilterCriterion)criterion;
String property = filterCriterion.getProperty();//要查询的属性
String value = (String)filterCriterion.getValue();//查询属性值
}
}
//TODO,根据上面客户端传过来的查询条件,查询数据库并返回查询结果
}
}
详细说明参考Java-API或Criteria对象使用说明
sortMode
在Grid或DataGrid中单击页眉中的列标题,Grid会自动根据当前列数据的大小正序或反序排列,如下图:
ID正序排列(注意id标题栏中的小三角图标):

ID反序排列(注意id标题栏中的小三角图标):

默认情况下这种排序机制是在客户端完成的,是基于客户端已有的数据所做的排序处理。
在分批数据下载机制下,如分页等,如果我们希望对所有的数据做排序处理,那么就需要设定DataGrid的sorgMode属性为serverSide:

采用serverSide的排序模式后,其排序机制的实现就要有Java后台完成了。在定义DataProvider代码的时候要声明com.bstek.dorado.data.provider.Criteria参数,相关排序的详细信息都包含在其中:
@DataProvider
public void getAll(Page<Order> page, Criteria criteria) throws Exception {
if (null!=criteria && criteria.getOrders().size()>0){
com.bstek.dorado.data.provider.Order propertyOrder = criteria.getOrders().get(0);
String property = propertyOrder.getProperty();//要排序的属性
boolean isDesc = propertyOrder.isDesc();//正序还是反序
//TODO,根据上面客户端传过来的排序设置,查询数据库并返回查询结果
}
}
上面的逻辑中你只要实现TODO中的代码就能实现一个serverSide的排序功能。
另外如果你是采用Hibernate中面向对象的开发模式,那还可以考虑使用Hibernate-addon中的工具类HibernateUtils实现:
@DataProvider
public void getAll(Page<Order> page, Criteria criteria) throws Exception {
DetachedCriteria detachedCriteria = DetachedCriteria
.forClass(Order.class);
if (criteria != null) {
orderDao.find(page,
HibernateUtils.createFilter(detachedCriteria, criteria));
} else {
orderDao.find(page);
}
}
HibernateUtils工具类会自动的将com.bstek.dorado.data.provider.Criteria参数转换为Hibernate中的org.hibernate.criterion.DetachedCriteria对象,简化代码的编写。
常用技巧
onRenderCell
通常我们都是利用DataColumn的onRenderCell实现单元格的渲染控制,如果我们想自定义单元格中的信息,如:显示超链接,显示图片,显示按钮,多个DataColumn中的值合并显示等等,这些都是通过onRenderCell事件实现的,并且其中最常用的一个js方法为xCreate,
下面我们列举其中的几种常见的场景(关于xCreate更详细的说明请参考client-api中的文档):
参考文档(自定义渲染的表格(sample-center))
表格超链接
效果如下:

实现办法
找到对应的DataColumn的onRenderCell事件:

其中编写代码:
jQuery(arg.dom).empty();
jQuery(arg.dom).xCreate({
tagName: "A",
href: "#",
content: arg.data.get("shipCountry"),
onclick: function() {
alert(arg.data.get("shipCountry"));
}
});
如果希望有多个链接,可以通过如下代码:
jQuery(arg.dom).empty();
jQuery(arg.dom).xCreate([{
tagName: "A",
href: "#",
content: arg.data.get("shipCountry") + "1",
onclick: function(){
alert(arg.data.get("shipCountry"));
}
},{
tagName: "A",
href: "#",
content: arg.data.get("shipCountry") + "2",
style:"padding-left:20px",
onclick: function(){
alert(arg.data.get("shipCountry"));
}
}
]);
数据格式化
显示效果如下的价格:

如果希望对数字或日期类型的数据做格式化的设置,可以通过DataColumn的displayFormat属性设置,如本例:

当然对于绑定DataSet的DataGrid中,我们更普遍的使用习惯还是将displayFormat配置到对应的DataType中,DataColumn中不设定displayFormat,让它自动的从DataType中获取。
自定义格式化
通过displayFormat可以做一些系统内置的格式化支持,可支持的格式化格式请参考jsdoc中的:
- Date的formatDate()
// @Bind #gridPhones.#price.onRenderCell
!function(arg) {
arg.dom.innerText = "平均:"
+ dorado.util.Common.formatFloat(arg.data.get("price"), "#,##0");//调用自定义格式化规则,并将计算结果设置到dom的innerText中。
}
表格多列合并显示
如下图中的"体积(mm)"列

它实际上是对象的三个属性拼合而成的字符串:

JS实现代码如:
//@Bind #gridPhones.#size.onRenderCell
!function(arg) {
var entity = arg.data;
arg.dom.innerText = entity.get("size.length") + " x " + entity.get("size.width") + " x " + entity.get("size.height");
}
表格中显示按钮
效果如下图中的operation数据列:

实现办法(在Grid的onCreate中设定自定义的DataColumn的renderer对象):
var OperationCellRenderer = $extend(dorado.widget.grid.SubControlCellRenderer,
{
createSubControl : function(arg) {
if (arg.data.rowType)
return null;
return new dorado.widget.Button({
toggleable : true,
onClick : function(self) {
var entity = arg.data, originPrice, price;
if (self.get("toggled")) {
originPrice = entity.get("price");
price = parseInt(originPrice * 0.8);
entity.set({
discount : true,
price : price,
originPrice : originPrice
});
} else {
originPrice = entity.get("price");
price = entity.get("originPrice");
entity.set({
discount : false,
price : price
});
}
dorado.widget.NotifyTipManager.notify(entity
.get("product")
+ "的价格已由" + originPrice + "调整为" + price + "!");
}
});
},
refreshSubControl : function(button, arg) {
var storage = arg.data.get("storage");
button.set({
caption : (storage > 0) ? "折扣" : "无货",
disabled : !(storage > 0),
toggled : arg.data.get("discount")
});
}
});
// @Bind #gridPhones.onCreate
!function(self) {
self.set("&operation.renderer", new OperationCellRenderer());
}
表格中显示图片
效果如下图中的图片列:

可以通过实现该类的onRenderCell事件实现:
// @Bind #gridPhones.#image.onRenderCell
!function(arg) {
$(arg.dom).empty().xCreate(
{
tagName : "IMG",
src : $url(">dorado/res/com/bstek/dorado/sample/data/images/"
+ arg.data.get("product") + "-24.png"),
style : "margin: 2px"
});
}
动态控制行只读或可编辑
DataGrid与DataSet绑定,当DataGrid定位行动作发生的时候会触发DataSet对应DataType的onCurrentChange事件,利用这种机制我们可以在onCurrentChange事件中动态控制Grid的可编辑特性:
// @Bind @Phone.onCurrentChange
!function(self, arg, gridPhones) {
if (arg.newCurrent && arg.newCurrent.get("storage")>100){
gridPhones.set("readOnly", true);
}else{
gridPhones.set("readOnly", false);
}
}
上面的gridPhones为页面上的DataGrid。
另外由于Dorado这种数据模型编程机制,如果我们直接设置DataSet的readOnly属性,它会导致与之绑定的其他可视化控件的只读状态发生变化,如DataGrid, TextEditor, AutoForm等等,因此在更多的情况下我们会将上面的代码改写为:
// @Bind @Phone.onCurrentChange
!function(self, arg, dsPhones) {
if (arg.newCurrent && arg.newCurrent.get("storage")>100){
dsPhones.set("readOnly", true);
}else{
dsPhones.set("readOnly", false);
}
}
根据行列动态决定某一个单元格只读或可编辑
与上面类似的,基于数据模型编码方式,如果想控制单个单元格的只读属性,可以通过如下方式设定:
// @Bind @Phone.onCurrentChange
!function(self, arg) {
if (arg.newCurrent && arg.newCurrent.get("storage")>100){
self.getPropertyDef("storage").set("readOnly", true);
}else{
self.getPropertyDef("storage").set("readOnly", false);
}
}
如何在服务器端动态的为Grid添加DataColumn
可以利用动态视图技术实现,首先为DataGrid控件定义一个监听器,listener属性设置好。listener定义方法参考:监听器。
参考代码:
public void onGridInit(DataGrid gridProduct) {
ColumnGroup columnGroup = new ColumnGroup();
columnGroup.setCaption("分组列");
DataColumn column1 = new DataColumn();
column1.setName("productId");
DataColumn column2 = new DataColumn();
column2.setName("productName");
columnGroup.addColumn(column2);
gridProduct.addColumn(columnGroup);
}
由于Dorado是基于数据模型管理数据的,因此你还要动态的创建DataType中对应的PropertyDef, 动态创建方法参考:动态私有DataType.
参考代码:
public void onInit(ViewConfig viewConfig) throws Exception {
PropertyDef propertyDef;
EntityDataType dataTypeProduct = (EntityDataType) viewConfig
.getDataType("Product");
propertyDef = new BasePropertyDef("productId");
propertyDef.setDataType(viewConfig.getDataType("long"));
propertyDef.setLabel("编码");
propertyDef.setReadOnly(true);
dataTypeProduct.addPropertyDef(propertyDef);
propertyDef = new BasePropertyDef("productName");
propertyDef.setLabel("名称");
dataTypeProduct.addPropertyDef(propertyDef);
}