ExtJs之GridPanel篇

前面写了几篇关于Ext基本知识的文章,估计大家都看烦了,但是个人认为对于初学者还是有些用的。从今天开始一起来探讨一些关于Ext的高级知识(其实也不算什么高级知识,只是相对前面的静态的东西来说从今天起会更多的说一些动态方面的内容)。

Ext中GridPanel和TreePanel都是常用的组件,被大量使用在Ext开发过程中,今天我们就先看看GridPanel吧。GridPanel的内容比较多,这里先看一些最常用的用法。大家都知道GridPanel是用来显示数据的,这里我会结合实际的开发做一个简单的demo来演示它的用法。值得一提的是对于GridPanel来说网上有较大一部分教程只是演示了GridPanel的基本绑定,而实际开发中不可能只是简单的绑定就能解决问题的,更多的时候需要通过不同的条件动态绑定而且多数牵扯到分页功能,而个人也是想尽可能全面对GridPanel做出介绍,所有上面说的这些都会在demo中出现。

前台代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head> <title>GridPanel</title> <link href="ext/resources/css/ext-all.css" mce_href="ext/resources/css/ext-all.css" rel="stylesheet" type="text/css" /> <mce:script src="ext/adapter/ext/ext-base.js" mce_src="ext/adapter/ext/ext-base.js" type="text/javascript"></mce:script> <mce:script src="ext/ext-all.js" mce_src="ext/ext-all.js" type="text/javascript"></mce:script> <mce:script type="text/javascript"><!-- Ext.onReady(function(){ var dtCategory=[ ['all','所有种类'], ['1','Beverages'], ['2','Condiments'], ['3','Confections'], ['4','Dairy Products'], ['5','Grains/Cereals'], ['6','Meat/Poultry '], ['7','Produce'], ['8','Seafood'] ]; var stCategory=new Ext.data.SimpleStore({ fields:['value','text'], data:dtCategory }); var cbCategory=new Ext.form.ComboBox({ id:"cbCategory", store:stCategory, displayField:"text", valueField:"value", typeAhead:true, mode:"local", triggerAction:"all", emptyText:"请选择商品种类...", editable:false, allowBlank:false, blankText:"商品种类必须选择", autoSelect:true, selectOnFoucus:true, value:'', dfval:'' }); cbCategory.setValue("all"); var tfName=new Ext.form.TextField({ id:'tfName' }); var btnSearch=new Ext.Button({ id:'btnSearch', iconCls:'btn_search', text:'搜索', handler:function(){ stProduct.load({params:{start:0,limit:10,categoryName:Ext.getCmp("cbCategory").getValue(),productName:Ext.getCmp("tfName").getValue()}});//注意参数传递 } }); var btnHelp=new Ext.Button({ text:'帮助', iconCls:'btn_help' }) var tb=new Ext.Toolbar({ id:'tb', items:[ '商品种类:', cbCategory, '-', '商品名称:', tfName, btnSearch, '->', btnHelp ] }); var pnNorth=new Ext.Panel({ id:'pnNorth', region:'north', autoHeight:true, items:[ tb ] }); var url="Default.aspx"; var stProduct=new Ext.data.Store({//定义数据存储容器,相当于客户端数据库 id:"st", proxy:new Ext.data.HttpProxy({url:url}),//请求代理,负责请求数据 reader:new Ext.data.JsonReader({totalProperty:"totalProperty",root:"root",fields:[{name:"ProductName"},{name:"CategoryName"},{name:'UnitPrice'},{name:'Discontinued'},{name:'QuantityPerUnit'},{name:'CompanyName'}] })//DataReader,负责解析数据 }); stProduct.load({params:{start:0,limit:10,categoryName:Ext.getCmp("cbCategory").getValue(),productName:Ext.getCmp("tfName").getValue()}});//加载数据 var cmProduct=new Ext.grid.ColumnModel([//列定义 new Ext.grid.RowNumberer(),//显示行号 {header:"产品名称",dataIndex:"ProductName",sortable:true},//每一列的列头,绑定字段,是否能够排序 {header:"产品种类",dataIndex:"CategoryName",sortable:true}, {header:"单价",dataIndex:"UnitPrice",sortable:true}, {header:"是否停产",dataIndex:"Discontinued",sortable:true}, {header:"规格",dataIndex:"QuantityPerUnit",sortable:true}, {header:"供货商",dataIndex:"CompanyName",sortable:true} ]); var pgtbProduct=new Ext.PagingToolbar({ id:"pgtbProduct", displayInfo:true, emptyMsg:"没有数据要显示!", displayMsg:"当前为第{0}--{1}条,共{2}条数据",//参数是固定的,分别是起始和结束记录数、总记录数 store:stProduct, pageSize:10 //每页显示记录数 }); var grdProduct=new Ext.grid.GridPanel({ id:"grdProduct", title:"商品信息", cm:cmProduct, store:stProduct, autoWidth: true, autoHeight:true, selModel:new Ext.grid.RowSelectionModel({single:true}), frame: true, pageSize:10, bbar:pgtbProduct, autoExpandColumn:6,//自动调整宽度的列数(这里为6就是说有列都自动调整列宽) loadMask:true // viewConfig:{ // forceFit:true // } }); var pnCenter=new Ext.Panel({ id:'pnCenter', region:'center', items:[ grdProduct ] }); var vp=new Ext.Viewport({ id:'vp', layout:'border', renderTo:Ext.getBody(), items:[ pnNorth, pnCenter ] }); } ); // --></mce:script> <mce:style type="text/css"><!-- .btn_search { background: url(ext/resources/images/cmj/btn_search.png) left top no-repeat !important; } .btn_help { background: url(ext/resources/images/cmj/btn_help.png) left top no-repeat !important; } --></mce:style><style type="text/css" mce_bogus="1"> .btn_search { background: url(ext/resources/images/cmj/btn_search.png) left top no-repeat !important; } .btn_help { background: url(ext/resources/images/cmj/btn_help.png) left top no-repeat !important; } </style> </head> <body> </body> </html>

后台代码:

using System; using System.Collections; using System.Configuration; using System.Data; using System.Linq; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Xml.Linq; using System.Web.Script.Serialization; using System.Collections.Generic; using System.Text; using Cmj.MyData; namespace GridPanel { public partial class _Default : System.Web.UI.Page { DBHelper dbHelper = new DBHelper(); int count; protected void Page_Load(object sender, EventArgs e) { int pageSize=10; int start=0; if (!string.IsNullOrEmpty(Request["limit"])) { pageSize = int.Parse(Request["limit"]); } if (!string.IsNullOrEmpty(Request["start"])) { start = int.Parse(Request["start"]); } if (start==0 && Request["categoryName"] != null && Request["productName"]!=null)//说明是查询而不是翻页 { Session["categoryID"] = Request["categoryName"]; Session["productName"] = Request["productName"]; } count = GetCount(Session["categoryID"].ToString(), Session["productName"].ToString()); Response.Write(GetJson(GetDataTabel(GetSql(Session["categoryID"].ToString(), Session["productName"].ToString()), pageSize, start), Session["categoryID"].ToString(), Session["productName"].ToString())); Response.End(); } private string GetSql(string categoryID,string productName) { string sql = "SELECT dbo.Products.ProductID, dbo.Products.ProductName,dbo.Categories.CategoryName,dbo.Products.UnitPrice,dbo.Products.Discontinued,dbo.Products.QuantityPerUnit,dbo.Suppliers.CompanyName FROM dbo.Products INNER JOIN dbo.Categories ON dbo.Products.CategoryID = dbo.Categories.CategoryID" + " INNER JOIN dbo.Suppliers ON dbo.Suppliers.SupplierID=dbo.Products.SupplierID "; if (categoryID != "all") { sql += "WHERE dbo.Categories.CategoryID='" + categoryID + "'"; } if(productName!=string.Empty) { sql+= " AND dbo.Products.ProductName like '%" + productName + "%'"; } return sql; } private int GetCount(string categoryID,string productName) { string sql = "SELECT dbo.Products.ProductID FROM dbo.Products INNER JOIN dbo.Categories ON dbo.Products.CategoryID = dbo.Categories.CategoryID" + " INNER JOIN dbo.Suppliers ON dbo.Suppliers.SupplierID=dbo.Products.SupplierID "; if (categoryID != "all") { sql += "WHERE dbo.Categories.CategoryID='" + categoryID + "'"; } if (productName != string.Empty) { sql += " AND dbo.Products.ProductName like '%" + productName + "%'"; } int count = dbHelper.GetDataTable(CommandType.Text, sql).Rows.Count; return count; } private DataTable GetDataTabel(string sql, int pageSize, int start) { PagingSQLHelperExtend psHelper = new PagingSQLHelperExtend(sql,"ProductID", "asc", pageSize); int currentPageIndex=start/pageSize+1; return dbHelper.GetDataTable(CommandType.Text, psHelper.GetSQL(currentPageIndex)); } private string GetJson(DataTable dt,string categoryID,string productName) { List<Customer> customers = new List<Customer>(); Customer customer; foreach (DataRow dr in dt.Rows) { customer = new Customer(); customer.ProductName = dr["ProductName"].ToString(); customer.CategoryName = dr["CategoryName"].ToString(); customer.UnitPrice = double.Parse(dr["UnitPrice"].ToString()); if (dr["Discontinued"].ToString() == "True") { customer.Discontinued = "是"; } else { customer.Discontinued = "否"; } customer.QuantityPerUnit = dr["QuantityPerUnit"].ToString(); customer.CompanyName = dr["CompanyName"].ToString(); customers.Add(customer); } JavaScriptSerializer jsSerializer = new JavaScriptSerializer(); StringBuilder sb = new StringBuilder("{ totalProperty:"); sb.Append(count); sb.Append(",root:"); sb.Append(jsSerializer.Serialize(customers)); sb.Append("}"); return sb.ToString(); } } }

上图对应的ajax请求数据(json格式):

{ totalProperty: 77, root: [ { "ProductName": "Queso Cabrales", "CategoryName": "Dairy Products", "UnitPrice": 21, "Discontinued": "否", "QuantityPerUnit": "1 kg pkg.", "CompanyName": "Cooperativa de Quesos /u0027Las Cabras/u0027" }, { "ProductName": "Queso Manchego La Pastora", "CategoryName": "Dairy Products", "UnitPrice": 38, "Discontinued": "否", "QuantityPerUnit": "10 - 500 g pkgs.", "CompanyName": "Cooperativa de Quesos /u0027Las Cabras/u0027" }, { "ProductName": "Konbu", "CategoryName": "Seafood", "UnitPrice": 6, "Discontinued": "否", "QuantityPerUnit": "2 kg box", "CompanyName": "Mayumi/u0027s" }, { "ProductName": "Tofu", "CategoryName": "Produce", "UnitPrice": 23.25, "Discontinued": "否", "QuantityPerUnit": "40 - 100 g pkgs.", "CompanyName": "Mayumi/u0027s" }, { "ProductName": "Genen Shouyu", "CategoryName": "Condiments", "UnitPrice": 15.5, "Discontinued": "否", "QuantityPerUnit": "24 - 250 ml bottles", "CompanyName": "Mayumi/u0027s" }, { "ProductName": "Pavlova", "CategoryName": "Confections", "UnitPrice": 17.45, "Discontinued": "否", "QuantityPerUnit": "32 - 500 g boxes", "CompanyName": "Pavlova, Ltd." }, { "ProductName": "Alice Mutton", "CategoryName": "Meat/Poultry", "UnitPrice": 39, "Discontinued": "是", "QuantityPerUnit": "20 - 1 kg tins", "CompanyName": "Pavlova, Ltd." }, { "ProductName": "Carnarvon Tigers", "CategoryName": "Seafood", "UnitPrice": 62.5, "Discontinued": "否", "QuantityPerUnit": "16 kg pkg.", "CompanyName": "Pavlova, Ltd." }, { "ProductName": "Teatime Chocolate Biscuits", "CategoryName": "Confections", "UnitPrice": 9.2, "Discontinued": "否", "QuantityPerUnit": "10 boxes x 12 pieces", "CompanyName": "Specialty Biscuits, Ltd." }, { "ProductName": "Sir Rodney/u0027s Marmalade", "CategoryName": "Confections", "UnitPrice": 81, "Discontinued": "否", "QuantityPerUnit": "30 gift boxes", "CompanyName": "Specialty Biscuits, Ltd." } ] }

Ext对于动态数据的处理方式可以说是固定的,通过DataProxy请求数据,使用DataReader解析数据,让后将解析的数据存储在Store中再绑定到组件上(这里暂不介绍对数据是如何处理的,我会专门找一节来说)。关于GridPanel的基本配置,我都添加了注释,这里主要说一下动态绑定和分页。按条件查询其本质就是根据不同条件获得不同数据,关键在于传参,而刚好Store的load方法就可以实现参数传递,另外我要说的一点就是Ext中其他组件也有很多类似的用法,所以要记住此方法。关于是否还有其他方法来实现动态传参,答案是肯定的,就是利用beforeload事件,这里就不做介绍了因为load方法在此就足够了,我们在TreePanle中会介绍另一种方法的。其次就是分页,Ext中分页控件会自动控制start参数(例如第一次start是0,单击下一页start就会自动变成下一页起始索引数),我们只需要在后台配合start来取不同页的数据即可。注意了这两方面之后接下来就是后台数据,在后台数据方面我们要构造固定格式(当然参数名可以任意取,只是形式必须要是固定的,否则前台无法显示)的Json数据,这里主要注意的就是在点击"下一页"、"上一页"等来翻页的时候后台只能够接收到load方法中的start和limit参数,其他参数(例如例子中的条件参数)是接收不到的,所以我在这里用session来存储条件(你当然也可使用其他方法),避免出现翻页的时候没有条件的状况。最后就是要记得在Ext中所有的Ajax请求(DataProxy是通过ajax来请求数据的)在返回的时候一定要在Response.Write()之后调用Response.End(),否则前台得不到数据,这一点或许其他js框架不需要,但是Ext中ajax请求是必须的。

为了方便大家学习,这里提供demo下载(数据库用的是Northwind,就不再提供了):GridPanel

注意:在后台代码中我用了自己类库中的一些类(主要是数据的读取和分页)来帮助构建Json,这些看不懂也没关系,对于GridPanel需要的数据就是"{totalProperty:23,root:[{ },{ },{ } ] }"这样的数据,你只要根据条件和分页构建这样的数据格式就可以了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值