標籤:回傳事件 ipostbackeventhandle 伺服器控制項
在使用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{ /// <summary> /// 表格連結按鈕列 /// </summary> [ToolboxItem(false)] [ParseChildren(true)] [PersistChildren(false)] public class LinkButtonField : BaseField { }}
註:LinkButtonField也是繼承自BaseField。添加了一個欄欄位後,我們就需要在列編輯器中,增加相應的類型,代碼如下:
[Designer("AspNetServerControl.Design.GridDesigner, AspNetServerControl.Design")] [ToolboxData("<{0}:Grid Title=\"Grid\" runat=\"server\"><Columns></Columns></{0}:Grid>")] [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<GridCommandEventArgs> 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(); /// <summary> /// 行內事件 /// </summary> [Category(CategoryName.ACTION)] [Description("行內事件")] public event EventHandler<GridCommandEventArgs> RowCommand { add { Events.AddHandler(_rowCommandHandlerKey, value); } remove { Events.RemoveHandler(_rowCommandHandlerKey, value); } } /// <summary> /// 觸發行內事件 /// </summary> /// <param name="e">事件參數</param> protected virtual void OnRowCommand(GridCommandEventArgs e) { EventHandler<GridCommandEventArgs> handler = Events[_rowCommandHandlerKey] as EventHandler<GridCommandEventArgs>; 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("<table id=\"{0}\" name=\"{1}\" rules=\"all\" border=\"1\" cellspacing=\"0\" style=\"width:100%;border-collapse:collapse;\">", UniqueID, UniqueID)); //RenderHeader(writer); RenderBody(writer); writer.Write("</table>"); } private void RenderBody(HtmlTextWriter writer) { DataTable dt = DataSource as DataTable; if (dt == null || dt.Rows.Count <= 0) { return; } writer.Write("<tbody>"); int rowIndex = 0; int columnIndex = 0; foreach (DataRow row in dt.Rows) { writer.Write(String.Format("<tr {0}>", GetRowStyle())); columnIndex = 0; foreach (GridColumn column in Columns) { if (column is LinkButtonField) { writer.Write(String.Format("<td {0}><a {1} name=\"{2}\">{3}</a></td>", GetItemStyle(column), GetLinkButtonPostBack(column as LinkButtonField, rowIndex, columnIndex), column.UniqueID, row[column.DataField])); } else { writer.Write(String.Format("<td {0}>{1}</td>", GetItemStyle(column), row[column.DataField])); } columnIndex++; } writer.Write("</tr>"); rowIndex++; } writer.Write("</tbody>"); } 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{ /// <summary> /// 表格行命令事件參數 /// </summary> public class GridCommandEventArgs : EventArgs { private int _rowIndex; /// <summary> /// 行索引 /// </summary> public int RowIndex { get { return _rowIndex; } set { _rowIndex = value; } } private int _columnIndex; /// <summary> /// 列索引 /// </summary> public int ColumnIndex { get { return _columnIndex; } set { _columnIndex = value; } } private string _commandName; /// <summary> /// 命令名稱 /// </summary> public string CommandName { get { return _commandName; } set { _commandName = value; } } private string _commandArgument; /// <summary> /// 命令參數 /// </summary> public string CommandArgument { get { return _commandArgument; } set { _commandArgument = value; } } /// <summary> /// 建構函式 /// </summary> /// <param name="rowIndex">行索引</param> /// <param name="columnIndex">列索引</param> /// <param name="commandName">命令名稱</param> /// <param name="commandArgument">命令參數</param> public GridCommandEventArgs(int rowIndex, int columnIndex, string commandName, string commandArgument) { _rowIndex = rowIndex; _columnIndex = columnIndex; _commandName = commandName; _commandArgument = commandArgument; } }}
在完成這些後,就可以使用了。
UI代碼如下:
<div> <S:Grid runat="server" ID="Grid_Edit" OnRowCommand="Grid_Edit_RowCommand"> <RowStyle Height="50px;" /> <Columns> <S:BoundField runat="server" ID="BoundField1" HeaderText="貨號" DataField="NO"> <ItemStyle HorizontalAlign="Center" /> </S:BoundField> <S:BoundField runat="server" ID="BoundField2" HeaderText="類型" DataField="Type"> <ItemStyle HorizontalAlign="Center" /> </S:BoundField> <S:BoundField runat="server" ID="BoundField3" HeaderText="狀態" DataField="Status"> <ItemStyle HorizontalAlign="Center" /> </S:BoundField> <S:LinkButtonField runat="server" ID="LinkButtonField1" HeaderText="連結" DataField="Link" CommandName="LINK"> </S:LinkButtonField> </Columns> </S:Grid> </div>
對應的後台代碼如下:
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", "食品", "已售完", "http://www.baidu.com" }); dt.Rows.Add(new String[] { "H10002", "蔬菜", "待銷售", "http://www.baidu.com" }); dt.Rows.Add(new String[] { "H10003", "水果", "待銷售", "http://www.baidu.com" }); dt.Rows.Add(new String[] { "H10004", "器具", "銷售中", "http://www.baidu.com" }); return dt; } protected void Grid_Edit_RowCommand(object sender, AspNetServerControl.GridCommandEventArgs e) { //需要處理的代碼 }這樣Grid的回傳事件就是實現了。其他的回傳處理,可以仿此。
Asp.Net伺服器控制項開發的Grid實現(四)回傳事件