其实工作之后做的第一个项目就不提倡使用服务器控件了,不过最近在维护公司的一个老系统,其中用到了GridView。
新需求是在GridView表头上添加排序功能。原有效果是不带分页的GridView,超出高度会显示滚动条,于是我就粗略判断此处数据量不大。采用的实现方法是直接取当前GridView的HTML作为XML数据源(IE下innerHtml获得的HTML字符串中属性值的双引号是没有的,所以此字符串不会识别成标准的XML,只有使用网上的自动补上双引号的方法才可作为XML使用),然后使用熟悉的XSLT进行排序。结果发布后没多久客服告诉我们用户反映排序很慢,问了测试人员才知道实际中有2000多条数据的情况……
这个系统的Sping.NET+NHibernate架构我还是刚开始接触,加之系统中的业务相当复杂,在改新功能的时候一直都比较谨慎,一直保持着尽量少改动原有方法的原则。在知道了新的问题之后,我采取的实现方法是,使用AJAX发送排序请求,后台排序之后再绑定GridView然后获得GridView的HTML返回到前台,前台使用JS更新列表。
其实页面中已经添加了GridView并且也绑定了数据,但是在实际测试的时候发现即使排序完成,IE状态栏的进度条却一直没有走完。当时判断是使用JS操作服务器控件GridView出现的问题,所以将前台的GridView删除了,而是在后台声明GridView并初始化、绑定。但是测试之后发现进度条没走完的情况依然存在,使用Fiddler监控发现每次排序完成都会请求一次csshover.htc文件,试着将查找引用csshover.htc文件的样式,发现正好是GridView的样式。于是移除此样式之后,进度条没走完的问题终于没有了。
后台指定GridView的ItemTemplate用到的模板类如下:
public class GridViewTextTemplate : ITemplate { private string templateTypeName; private string columnName; private string Id; public GridViewTextTemplate(string typeStr, string colname, string controlId) { templateTypeName = typeStr; columnName = colname; Id = controlId; } public void InstantiateIn(System.Web.UI.Control container) { switch (templateTypeName) { case "CheckBox": CheckBox checkBox = new CheckBox(); checkBox.ID = Id; container.Controls.Add(checkBox); break; case "Label": Label label = new Label(); label.ID = Id; label.DataBinding += new EventHandler(this.OnDataBinding); container.Controls.Add(label); break; case "HiddenField&LableInPanel": HiddenField hiddenField = new HiddenField(); hiddenField.ID = "RecordID"; hiddenField.DataBinding += new EventHandler(this.OnDataBinding); container.Controls.Add(hiddenField); Panel panel = new Panel(); panel.CssClass = "panleStyle"; Label labelInPanel = new Label(); labelInPanel.ID = Id; labelInPanel.DataBinding += new EventHandler(this.OnDataBinding); panel.Controls.Add(labelInPanel); container.Controls.Add(panel); break; default: break; } } private void OnDataBinding(Object sender, EventArgs e) { GridViewRow row; if (columnName != "") { switch (templateTypeName) { case "Label": Label labelInPanel = (Label)sender; row = (GridViewRow)labelInPanel.NamingContainer; labelInPanel.Text = Convert.ToDateTime(DataBinder.Eval(row.DataItem, columnName)).ToString("yyyy-MM-dd"); break; case "HiddenField&LableInPanel": if (sender is HiddenField) { HiddenField hiddenField = (HiddenField)sender; row = (GridViewRow)hiddenField.NamingContainer; hiddenField.Value = DataBinder.Eval(row.DataItem, "ID").ToString(); break; } else if (sender is Label) { Label label = (Label)sender; row = (GridViewRow)label.NamingContainer; label.Text = DataBinder.Eval(row.DataItem, "RecordNo").ToString().Length > 18 ? DataBinder.Eval(row.DataItem, "RecordNo").ToString().Substring(0, 18) + "..." : DataBinder.Eval(row.DataItem, "RecordNo").ToString(); } break; default: break; } } } }
使用:
private GridView GetRecordGridView() { GridView grid_Record = new GridView(); grid_Record.ID = "grid_Record"; grid_Record.Width = 260; grid_Record.AutoGenerateColumns = false; grid_Record.DataKeyNames = new string[] { "Id" }; grid_Record.CssClass = "listGridView"; TemplateField col_chose = new TemplateField(); col_chose.HeaderText = "选择"; col_chose.ItemTemplate = new GridViewTextTemplate("CheckBox", "", "chkRecord"); grid_Record.Columns.Add(col_chose); TemplateField col_recordID = new TemplateField(); col_recordID.HeaderText = "单号"; //col_recordID.ItemTemplate = new GridViewTextTemplate("HiddenField", "ID", "RecordID"); col_recordID.ItemTemplate = new GridViewTextTemplate("HiddenField&LableInPanel", "RecordNo", "lblRecordNo"); grid_Record.Columns.Add(col_recordID); TemplateField col_saveDate = new TemplateField(); col_saveDate.HeaderText = "日期"; col_saveDate.ItemTemplate = new GridViewTextTemplate("Label", "SaveDate", "lblSaveDate"); grid_Record.Columns.Add(col_saveDate); return grid_Record; }
获取GridView的HTML的方法:
public string RenderGridView(GridView grid) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); System.IO.StringWriter sw = new System.IO.StringWriter(sb); HtmlTextWriter htw = new HtmlTextWriter(sw); grid.RenderControl(htw); return sb.ToString(); }