实际的应用的总是遇到 GrideView 需要动态生成一些数据列,也许是简单的绑定列,更多时候会是特殊的模板列。我们不得不使用代码生成自定义的模板列。 其实模板列的概念倒是很简单,通过ASP的前台代码,我们很容易看出来模板列的结构,
TemplateField = HeaderTemplate + ItemTemplate (列模板 = 标题模板 + 子项模板) 模板只要是实现 ITemplate
接口,并根据需要实现 DataBind 的方法就可以了。
主要是自定义列数据绑定的问题,百度了很多,说法很多,有的说不建议使用自定义的模板列,因为从后台无法获取到值,还有把数据绑定的方法强制地指定到GrideView的DataRow_Bind的事件中,越看越迷茫,最后终于到 上找到答案,通过代码也似乎领悟的GrideView单元格绑定的逻辑过程。 GrideView行绑定到达单元格中时,会调用我们指定的绑定方法为单元格中的控件赋值。默认的情况下当然是使用 DataField 中我们指定的的值进行绑定,但如果我们指定了绑定模板,它就会调用模版中 自定义控件 指定的 DataBing 方法。就是我们在控件事件中看到的这个:
在学校的还是照着课本打代码的时候,我就很好奇这个事件是做什么用的、又如何使用,每一个控件都会有,但是直到俩年后的现在猜恍然大悟(大家不要喷饭哈)
想到这里数据绑定的问题也就解决了!说了一大通很罗嗦把,大家可以直接参考代码
using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.UI;using System.Web.UI.WebControls;using System.Data;namespace SSRISManager.BasePage{ ////// 超链接列的模板 /// public class TemplateFieldColumn : TemplateField { private ItemTemplateLabel myHeaderTemplate = null; private ItemTemplateLinkBtn myFieldTemplate = null; public TemplateFieldColumn(string headerText, string fieldNmae,string formatString) : base() { myFieldTemplate = new ItemTemplateLinkBtn(headerText, formatString, fieldNmae); myHeaderTemplate = new ItemTemplateLabel(headerText); this.ItemTemplate = myFieldTemplate; this.HeaderTemplate = myHeaderTemplate; } }#region Item Template for Link Button////// 为超链接创建模板元素/// public class ItemTemplateLinkBtn : ITemplate{ string strColumnText; string FieldGuid; string FormatString; ////// 构造函数 /// /// 列名 /// URL格式化字符串 /// 绑定的列名(暂时只支持一个) public ItemTemplateLinkBtn(string ColText, string navigateURL, string ColumnGuid) { this.strColumnText = ColText; this.FormatString = navigateURL; this.FieldGuid = ColumnGuid; } ////// 实例化单元格 /// /// public void InstantiateIn(Control objContainer) { HyperLink lnkbtn = new HyperLink(); lnkbtn.DataBinding += new EventHandler(lnkbtn_DataBinding); lnkbtn.ToolTip = "点击进去编辑"; objContainer.Controls.Add(lnkbtn); } ////// 数据绑定时执行的操作 /// /// /// private void lnkbtn_DataBinding(object sender, EventArgs e) { HyperLink lnkbtn = (HyperLink)sender; // 此处类型转换时请注意使用正确的类型 GrideView ->GridViewRow || DataView GridViewRow container = (GridViewRow)lnkbtn.NamingContainer; object valuePara = ((DataRowView)container.DataItem)[this.FieldGuid]; lnkbtn.Text = valuePara.ToString(); // 设置格话后的参数 lnkbtn.NavigateUrl = string.Format(FormatString, valuePara); }}#endregion#region Item Template for Label////// 创建标签模板/// public class ItemTemplateLabel : ITemplate{ string strColumnText; string strLabelName; public ItemTemplateLabel(string ColText) { this.strColumnText = ColText; } public ItemTemplateLabel(string ColText, string LabelName) { this.strColumnText = ColText; this.strLabelName = LabelName; } ////// 创建单元格实例 /// /// public void InstantiateIn(Control objContainer) { Label lbl = new Label(); lbl.ID = strLabelName; lbl.DataBinding += new EventHandler(lbl_DataBinding); objContainer.Controls.Add(lbl); } ////// 执行绑定 /// /// /// private void lbl_DataBinding(object sender, EventArgs e) { Label lbl = (Label)sender; //lbl.ID = strLabelName; lbl.Text = strColumnText; }}#endregion
}
有了这个类我们在创建模板列的时候就像创建一个普通的类一样容易了。
// 格式化的字符串 string formatString = "ModuleEditMaster.aspx?PAGEID=" + PageID + "&GUID={0}"; // 创建模板列 TemplateFieldColumn pTemplate = new TemplateFieldColumn(column.Header, column.ColumnName, formatString); // 可以设置你像要的显示效果 pTemplate.HeaderStyle.Width = 60; pTemplate.ItemStyle.HorizontalAlign = HorizontalAlign.Center; // 加入到数据表格 gdvPageView.Columns.Add(pTemplate);
到这里 大功告成!
模板列在 PostBack 后消失的问题
【模板列的创建应在 GrideView_Init
或者 Page_Init
事件中创建来避免 PostBack
后消失的问题】 仔细去看的时候发现其实模板列并没有消失,只是中间我们定义的控件消失了,但是同样是动态创建的 BoundField 类型的普通列并没有异常,猜想应该是我们自定义的控件状态没有被保存,而BoundField 的内容可能会包含某种标记( IStateManager
)而被.Net 框架保存处理了。 所以我们被迫每次都要在数据绑定前重新定义模板列的内容。建议在GrideView_Init
或者 Page_Init
事件中创建。