Asp.Net服务器控件开发的Grid实现(四)回发事件
在使用Grid的时候,会用到链接跳转。如果只是普通的链接跳转,那只要使用a标签的href就可以实现。但是有时,我们希望在链接跳转的时候,能够引发回发事件,在后台作出一定的处理,然后再跳转。这样要如何实现呢?我们可以定义一个LinkButtonField来实现。代码如下
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web.UI; namespace AspNetServerControl { /// /// 表格链接按钮列 /// [ToolboxItem(false)] [ParseChildren(true)] [PersistChildren(false)] public class LinkButtonField : BaseField { } }
注:LinkButtonField也是继承自BaseField。添加了一个列字段后,我们就需要在列编辑器中,增加相应的类型,代码如下:
[Designer("AspNetServerControl.Design.GridDesigner, AspNetServerControl.Design")] [ToolboxData("")] [ToolboxBitmap(typeof(Grid), "toolbox.Grid.bmp")] [Description("表格控件")] [ParseChildren(true)] [PersistChildren(false)] [ControlBuilder(typeof(NotAllowWhitespaceLiteralsBuilder))] [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")] public class Grid : ControlBase, IPostBackEventHandler { ///属性代码请参照《 Asp.Net服务器控件开发的Grid实现(二)Html标记渲染》 #region 事件 #region OnRowCommand //// Defines the Click event. //public event EventHandler RowCommand; ////Invoke delegates registered with the Click event. //protected virtual void OnRowCommand(GridCommandEventArgs e) //{ // if (RowCommand != null) // { // RowCommand(this, e); // } //} private static readonly object _rowCommandHandlerKey = new object(); /// /// 行内事件 /// [Category(CategoryName.ACTION)] [Description("行内事件")] public event EventHandler RowCommand { add { Events.AddHandler(_rowCommandHandlerKey, value); } remove { Events.RemoveHandler(_rowCommandHandlerKey, value); } } /// /// 触发行内事件 /// /// 事件参数 protected virtual void OnRowCommand(GridCommandEventArgs e) { EventHandler handler = Events[_rowCommandHandlerKey] as EventHandler; if (handler != null) { handler(this, e); } } #endregion #endregion protected override void Render(HtmlTextWriter writer) { base.Render(writer); if (_columns == null) { return; } writer.Write( String.Format("", UniqueID, UniqueID)); //RenderHeader(writer); RenderBody(writer); writer.Write(""); } private void RenderBody(HtmlTextWriter writer) { DataTable dt = DataSource as DataTable; if (dt == null || dt.Rows.Count "); int rowIndex = 0; int columnIndex = 0; foreach (DataRow row in dt.Rows) { writer.Write(String.Format("", GetRowStyle())); columnIndex = 0; foreach (GridColumn column in Columns) { if (column is LinkButtonField) { writer.Write(String.Format("{3}", GetItemStyle(column), GetLinkButtonPostBack(column as LinkButtonField, rowIndex, columnIndex), column.UniqueID, row[column.DataField])); } else { writer.Write(String.Format("{1}", GetItemStyle(column), row[column.DataField])); } columnIndex++; } writer.Write(""); rowIndex++; } writer.Write(""); } private String GetLinkButtonPostBack(LinkButtonField linkButton, int rowIndex, int columnIndex) { if (linkButton == null) { return ""; } String arg = String.Format("Command${0}${1}${2}${3}", rowIndex, columnIndex, linkButton.CommandName, linkButton.CommandArgument); String clientScript = Page.ClientScript.GetPostBackClientHyperlink(this, arg); String href = String.Format("href=\"{0}\"", clientScript); return href; } ///其他代码请参照《 Asp.Net服务器控件开发的Grid实现(二)Html标记渲染》 public void RaisePostBackEvent(string eventArgument) { if (eventArgument.StartsWith("Command$")) { string[] commandArgs = eventArgument.Split('$'); if (commandArgs.Length == 5) { GridCommandEventArgs gridCommandEventArgs = new GridCommandEventArgs(Convert.ToInt32(commandArgs[1]), Convert.ToInt32(commandArgs[2]), commandArgs[3], commandArgs[4]); OnRowCommand(gridCommandEventArgs); } } }
注:
1.IPostBackEventHandler接口需要实现RaisePostBackEvent方法。
2.在页面回发时,是通过控件的name来索引到对应的事件,然后回发到目标的。所以对于Grid控件,我们必须要在Render的时候将name赋值,然后在生成回发脚本时将其对应上。
(1)所以在Render函数的table标记的name要赋值,这里使用UniqueID以确保唯一性。
(2)同时在RenderBody时,如果是LinkButtonField的列,就增加回发脚本。即将LinkButtonField渲染到表格的单元格中时,使用a标记渲染,同时将其href赋值相应的脚本。在GetLinkButtonPostBack中生成相应的回发脚本。
(3)GetLinkButtonPostBack函数中,将单元格的列索引和行索引以及LinkButtonField的CommandName和CommandArgument一同作为回发参数。同时,为了便于区分,使用Command作为前缀,并以$作为参数间的分隔符。使用Page.ClientScript.GetPostBackClientHyperlink来生成回发的js脚本,使用该系统方法相应简单,当然也可以直接写出脚本,代码如下。
javascript:__doPostBack('Grid_Edit','Command$0$3$LINK$cmdarg'
3.在RaisePostBackEvent收到回发事件后,将相应的参数分离出来,并作相应的处理。为了参够让使用Grid自定义回发后调用的事件,我们自定义了一个OnRowCommand事件。
4.OnRowCommand事件由三个部分主成。
(1)唯一KEY:使用静态只读的object,即_rowCommandHandlerKey。
(2)将事件添加到委托事件的处理列表中,即RowCommand中。也有直接使用委托来定义的,但性能上不及这种定义。委托直接定义的,原则上是线程安全些。为了能够更好的自定义事件,我们定义了一个事件参数GridCommandEventArgs。代码见后文。
(3)使用Grid的开发者实现的OnRowCommand事件,相当于是按钮的OnClick事件。注意,此事件的命名必须与前面的委托相对应,即只在前面增加一个On。
GridCommandEventArgs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AspNetServerControl { /// /// 表格行命令事件参数 /// public class GridCommandEventArgs : EventArgs { private int _rowIndex; /// /// 行索引 /// public int RowIndex { get { return _rowIndex; } set { _rowIndex = value; } } private int _columnIndex; /// /// 列索引 /// public int ColumnIndex { get { return _columnIndex; } set { _columnIndex = value; } } private string _commandName; /// /// 命令名称 /// public string CommandName { get { return _commandName; } set { _commandName = value; } } private string _commandArgument; /// /// 命令参数 /// public string CommandArgument { get { return _commandArgument; } set { _commandArgument = value; } } /// /// 构造函数 /// /// 行索引 /// 列索引 /// 命令名称 /// 命令参数 public GridCommandEventArgs(int rowIndex, int columnIndex, string commandName, string commandArgument) { _rowIndex = rowIndex; _columnIndex = columnIndex; _commandName = commandName; _commandArgument = commandArgument; } } }
在完成这些后,就可以使用了。
UI代码如下:
对应的后台代码如下:
private void InitLoad() { Grid_Edit.DataSource = GenerateData(); } private DataTable GenerateData() { DataTable dt = new DataTable(); dt.Columns.Add("NO"); dt.Columns.Add("Type"); dt.Columns.Add("Status"); dt.Columns.Add("Link"); dt.Rows.Add(new String[] { "H10001", "食品", "已售完", "https://www.baidu.com" }); dt.Rows.Add(new String[] { "H10002", "蔬菜", "待销售", "https://www.baidu.com" }); dt.Rows.Add(new String[] { "H10003", "水果", "待销售", "https://www.baidu.com" }); dt.Rows.Add(new String[] { "H10004", "器具", "销售中", "https://www.baidu.com" }); return dt; } protected void Grid_Edit_RowCommand(object sender, AspNetServerControl.GridCommandEventArgs e) { //需要处理的代码 }这样Grid的回发事件就是实现了。其他的回发处理,可以仿此。