2011年6月1日星期三

  Ext4核心组件Grid的变化及学习(4):grid与服务端使用direct进行数据交互

大部分grid的数据都是要提交到后台服务端的,现在一种比较好用的方式就是direct。今天介绍一下这种交互方式的实现。

例子如下:

sqlserver数据库中两张表通过外键关联:

文件信息FileInfo

image

文件类别FileClass

image

需要做出的效果如下:

显示

image

下拉框修改

image

修改之后自动上传

image

1、服务端添加Ext.Direct.dll和Newtonsoft.Json.dll的引用

2、处理文件数据的类FileAction.cs,注意最后一个Update方法

   using  System; using  System.Collections.Generic; using  Ext.Direct; using  Newtonsoft.Json; using  Newtonsoft.Json.Linq; using  System.Web.SessionState; using  DBUtility; using  System.Data; using  System.Text; using  System.Data.SqlClient; using  Persister; ///        /// FileAction 的摘要说明 ///     [DirectAction] public   class  FileAction{ [DirectMethod]  public  FileInfoSerializer Load(Dictionary < string , object >  arg) {  object [] sorters  =  ( object [])arg[ " sort " ]; Dictionary < string ,  object >  sorter  =  (Dictionary < string ,  object > )sorters[ 0 ]; FileInfoCollection coll  =   new  FileInfoCollection(); coll.OrderField  =  sorter[ " property " ].ToString(); coll.OrderDirection  =  sorter[ " direction " ].ToString().ToLower()  ==   " desc "   ?  FileInfoCollection.Direction.DESC : FileInfoCollection.Direction.ASC;  return   new  FileInfoSerializer(coll); } [DirectMethod]  public  FileInfoSerializer PagingLoad( string  order,  string  direction,  long  start,  long  limit) { FileInfoCollection coll  =   new  FileInfoCollection(); coll.OrderField  =  order; coll.OrderDirection  =  direction.ToLower()  ==   " desc "   ?  FileInfoCollection.Direction.DESC : FileInfoCollection.Direction.ASC;  return   new  FileInfoSerializer(coll, Convert.ToInt32(start), Convert.ToInt32(limit)); } [DirectMethod] [ParseAsJson]  public  JObject Destroy(JObject o) { JValue val  =  (JValue)o[ " data " ]; FileInfo c  =   new  FileInfo(Convert.ToString(val.Value)); c.Destroy();  return   new  JObject(  new  JProperty( " data " ,  new  JArray()) ); } [DirectMethod] [ParseAsJson]  public  FileInfo Create(JObject o) { FileInfo c  =  JsonConvert.DeserializeObject < FileInfo > (o.ToString()); c.Save();  return  c; } [DirectMethod] [ParseAsJson]  public  JObject Update(JObject o) { FileInfo c  =  JsonConvert.DeserializeObject < FileInfo > (o.ToString()); JProperty success  =   new  JProperty( " success " , " false " );  try  { c.Save(); success  =   new  JProperty( " success " ,  " true " ); }  catch  { }  return   new  JObject( success,  new  JProperty( " id " ,c.Id),  new  JProperty( " title " ,c.Title) ); }}    

3、统一调用接口Api.ashx

   <% @ WebHandler Language = " C# "  Class = " Api "   %>  using  System; using  System.Collections.Generic; using  System.Linq; using  System.Web.SessionState; using  System.Web; using  Ext.Direct; public   class  Api : DirectHandler, IRequiresSessionState{  public   override   string  ProviderName {  get  {  return   " Ext.app.USER_API " ; } }  public   override   string  Namespace {  get  {  return   " MyApp " ; } }  protected   override   void  ConfigureProvider(DirectProvider provider) {  this .Configure(provider,  new   object [] {  new  CheckLogin(), new  TreeAction(), new  FileAction() }); }}    

服务器端不是重点,主要看一下update方法返回的数据,之后会找时间系统讲一下服务器端direct,重点看下js文件:

因为是测试,所以就临时把fileClass建好了进行数据调用,正式使用的时候和file表一样要从服务端取,这个调用方式有很多种,之后会开篇帖子就这个进行深入讨论,不是今天的重点。

4、定义FileModel,里面的时间数据要进行转换

   Ext.define( ' File ' , { extend:  ' Ext.data.Model ' , fields: [  ' id ' , ' title ' ,  ' classId ' , {name:  ' datetimeCreated ' ,type:  ' date ' ,dateFormat:  ' c ' },  ' docAbstract ' , ' typeId '  ]});    

5、定义fileClass(临时内存数据,之后会开篇帖子就这个进行深入讨论)

   // 定义fileClassModel  Ext.define( ' FileClass ' , { extend:  ' Ext.data.Model ' , fields: [ ' id ' ,  ' name ' ]}); // 创建fileClass下拉选择框的store  new  Ext.data.Store({ model:  ' FileClass ' , storeId: ' fileClassStore ' , proxy: {type:  ' memory ' }, data : [ { " id " : " 1e887509-dd86-49f4-9d63-4e8640409758 " ,  " name " : " .Net " }, { " id " : " 3384fcb7-3106-4fdd-ab65-31152eef9edb " ,  " name " : " java " } ] });    

6、创建filesStore和filesStore的callback function,如果不需要callback,也可以直接在api里面写调用的函数。具体为什么这么写请参考我写的这篇帖子

Ext.data.DirectStore中DirectAction的回调函数问题 
   // 创建filesStore的callback function  var callback  =  function(response, e) {  if (response.success == ' true ' ){ Ext.getStore( ' filesStore ' ).getById(response.id).commit() Ext.MessageBox.alert( ' callback ' ,response.title + ' 已经更新 ' ) }  else { Ext.getStore( ' filesStore ' ).getById(response.id).reject() Ext.MessageBox.alert( ' callback ' ,response.title + ' 更新失败 ' ) }}; // 创建filesStore  Ext.create( ' Ext.data.DirectStore ' , { model:  ' File ' , storeId:  ' filesStore ' , autoLoad:  true , autoSync:  true , remoteSort:  true , api: { create: MyApp.FileAction.Create, read: MyApp.FileAction.Load, update: function(rec){MyApp.FileAction.Update(rec,callback);}, destroy: MyApp.FileAction.Destroy }, writer:  new  Ext.data.JsonWriter({ encode:  false , writeAllFields:  true  }), idProperty:  ' id ' , totalProperty:  ' total ' , root:  ' data ' , sorters: [{ property:  ' datetimeCreated ' , direction:  ' DESC '  }] });    

有几个需要注意的config:

a)autoSync: true 每修改好一行就直接提交到服务端,我一般都选这种,可以节省客户的时间,不需要很长时间的等待。

b)storeId: 'filesStore' 会把这个store注册到ext的storemanager,之后可以使用Ext.getStore('filesStore')访问

接下来就是grid的设置:

   // 定义MainFileGrid  Ext.define( ' App.MainFileGrid ' , { extend:  ' Ext.grid.Panel ' , store:  ' filesStore ' , alias:  ' widget.MainFileGrid ' , columns: [ { header:  ' 文档 ' , dataIndex:  ' title ' , flex:  1 , renderer:  function (value, o, record) {  return  Ext.String.format( '   
{0} {1}  ' , value, record.get( ' author ' )); }, editor: {  //  defaults to textfield if no xtype is supplied   allowBlank:  false  } }, { header:  ' 类别 ' , flex:  1 , dataIndex:  ' classId ' , width:  100 , renderer:  function (value) {  return  Ext.getStore( ' fileClassStore ' ).getById(value).data.name; }, field: { xtype:  ' combobox ' , store:  ' fileClassStore ' , queryMode:  ' local ' ,  // 提前加载数据,防止延迟   autoRender:  true , displayField:  ' name ' , valueField:  ' id ' , editable:  false , allowBlank:  false  } }, { header:  ' 文件类型 ' , flex:  1 , dataIndex:  ' typeId ' , width:  70 , align:  ' right ' , editor: {  //  defaults to textfield if no xtype is supplied   allowBlank:  false  } }, { header:  ' 时间 ' , dataIndex:  ' datetimeCreated ' , renderer : Ext.util.Format.dateRenderer( ' Y年m月d日 ' ), width:  150 , field: { xtype:  ' datefield ' , allowBlank:  false , format:  ' m/d/Y ' , minValue:  ' 01/01/2006 ' , minText:  ' Cannot have a start date before the company existed! ' , maxValue: Ext.Date.format( new  Date(),  ' m/d/Y ' ) } } ], plugins: [Ext.create( ' Ext.grid.plugin.RowEditing ' , { autoCancel:  false , clicksToEdit:  2  })], initComponent:  function (){ Ext.apply( this , { dockedItems: [{ xtype:  ' toolbar ' , cls:  ' x-docked-noborder-top ' , items: [{ text:  ' 新文件 ' , iconCls:  ' icon-new-topic ' , handler:  function (){ alert( ' Not implemented ' ); } },  ' - ' , { text:  ' 显示详细信息 ' , iconCls:  ' icon-preview ' , enableToggle:  true , pressed:  true , scope:  this , toggleHandler:  this .onPreviewChange }] },{ dock:  ' bottom ' , xtype:  ' pagingtoolbar ' , store:  ' filesStore ' , displayInfo:  true , displayMsg:  ' 显示 {0} - {1} 共 {2} 文档 ' , emptyMsg:  ' 无文档 '  }], selModel: Ext.create( ' Ext.selection.RowModel ' , { mode:  ' SINGLE ' , listeners: { scope:  this , select:  this .onSelect } }) });  this .callParent(); }, onSelect:  function (selModel, rec){  this .ownerCt.onSelect(rec); }, loadForum:  function (id){  var  store  =   this .store; store.getProxy().extraParams.forumId  =  id; store.loadPage( 1 ); }, onPreviewChange:  function (btn, pressed){  this .ownerCt.togglePreview(pressed); }, onSummaryChange:  function (btn, pressed){  this .getView().getPlugin( ' preview ' ).toggleExpanded(pressed); }});    

 

需要注意的是以下几点:

a)“类别”列自定义显示,根据类别id到类别store中找name

renderer: function(value) {
               return Ext.getStore('fileClassStore').getById(value).data.name;
          },

如果不设置就会直接显示id,效果对比如下(其中文件类型就是没有自定义的,显示原始id)

image

b)“类别”列的修改模式采用下拉框,只允许选择不允许输入,不能为空,而且建议提前渲染,不然第一次点击会出现空值

   field: { xtype:  ' combobox ' , store:  ' fileClassStore ' , queryMode:  ' local ' ,  // 提前加载数据,防止延迟   autoRender:  true , displayField:  ' name ' , valueField:  ' id ' , editable:  false , allowBlank:  false }    

没有评论:

发表评论