zoukankan      html  css  js  c++  java
  • 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
    {
        /// <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="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的回发事件就是实现了。其他的回发处理,可以仿此。




  • 相关阅读:
    Android-调用优酷SDK上传视频
    新浪微博客户端(16)-获得并显示用户昵称
    新浪微博客户端(15)-保存用户名和密码
    转:Java NIO系列教程(九) Pipe
    新浪微博客户端(14)-截取回调地址中的授权成功的请求标记,换取access_token
    iOS-AFN "Request failed: unacceptable content-type: text/plain"
    新浪微博客户端(13)-使用UIWebView加载OAuth授权界面
    iOS-(kCFStreamErrorDomainSSL, -9802)
    转:Java NIO系列教程(八) DatagramChannel
    转:Java NIO系列教程(七) Socket Channel
  • 原文地址:https://www.cnblogs.com/sparkleDai/p/7604980.html
Copyright © 2011-2022 走看看