欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Asp.Net服务器控件开发的Grid实现(四)回发事件

程序员文章站 2022-05-01 17:35:49
在使用Grid的时候,会用到链接跳转。如果只是普通的链接跳转,那只要使用a标签的href就可以实现。但是有时,我们希望在链接跳转的时候,能够引发回发事件,在后台作出一定的处理,然后...

在使用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的回发事件就是实现了。其他的回发处理,可以仿此。