GridView既强大又好用。为了让它更强大、更好用,我们来写一个继承自GridView的控件。
[索引页]
[×××]


扩展GridView控件(9) - 给数据行增加右键菜单


作者: webabcd
InBlock.gif /*正式版的实现 开始*/
 
介绍
扩展GridView控件:
给数据行增加右键菜单,响应服务端事件或超级链接

使用方法(设置ContextMenus集合属性): 
Text - 菜单的文本内容
BoundCommandName - 需要绑定的CommandName
NavigateUrl - 链接的URL
Target - 链接的目标窗口或框架
SmartGridView的属性ContextMenuCssClass - 右键菜单的级联样式表 CSS 类名(右键菜单的结构div ul li a)


关键代码
js
/*右键菜单 开始*/
yy_sgv_rightMenu = function ()
{
/// <summary>构造函数</summary>

         this._menu = null;
         this._menuItem = null;
         this._handle = null;
         this._target = null;
         this._cssClass = null
};

yy_sgv_rightMenu.prototype =    
{
/// <summary>相关属性和相关方法</summary>

        get_menu: function()    
        {
                 return this._menu;
        },
        set_menu: function(value)
        {
                 this._menu = value;
        },
        
        get_handle: function()    
        {
                 return this._handle;
        },
        set_handle: function(value)
        {
                 this._handle = value;
        },
        
        get_target: function()    
        {
                 return this._target;
        },
        set_target: function(value)
        {
                 this._target = value;
        },
        
        get_cssClass: function()    
        {
                 return this._cssClass;
        },
        set_cssClass: function(value)
        {
                 this._cssClass = value;
        },
        
        get_menuItem: function()    
        {
                 return this._menuItem;
        },
        set_menuItem: function(value)
        {
                 this._menuItem = value;
        },


        show: function(e)
        {
                 if ( this.get_menuItem() == null)    
                {
                         this.hidden();
                         return true;
                }
        
                 var rightMenu = this.get_menu();
                 if (rightMenu == null)
                {
                        rightMenu = document.createElement( "div");
                }

                 var menuInnerHTML = ""; // 菜单容器里的HTML内容
                 var $items = this.get_menuItem();
                 var $handle = this.get_handle();
                 var $target = this.get_target();
                
                rightMenu.className = "yy_sgv_rightMenuBase";    
                 if ( this.get_cssClass() == null || this.get_cssClass() == "")
                        rightMenu.className += " " + "yy_sgv_rightMenu";
                 else
                        rightMenu.className += " " + this.get_cssClass();                        
                
                menuInnerHTML += "<ul>";
                
                 for ( var i in $items)
                {
                         if ($items[i].indexOf( "<hr") != -1)
                        {
                                menuInnerHTML += $items[i];
                        }
                         else
                        {
                                 if ($target[i] == "")
                                {
                                        $target[i] = "_self";
                                }
                        
                                menuInnerHTML += "<li><a href=\"" + $handle[i] + "\" target=\"" + $target[i] + "\">";
                                menuInnerHTML += $items[i];
                                menuInnerHTML += "</a></li>";        
                        }
                }
                
                menuInnerHTML += "</ul>";
                 // alert(menuInnerHTML);
                
                rightMenu.innerHTML = menuInnerHTML;
                
                rightMenu.style.visibility = "visible";
                
                rightMenu. = function(e)
                {
                        e=e||window.event;
                        document.all ? e.cancelBubble = true : e.stopPropagation();
                }
                
                rightMenu.onselectstart = function()
                {
                         return false;
                }
                
                document.body.appendChild(rightMenu);
                 this.set_menu(rightMenu); // 方便别的方法引用

                e = e || window.event;
                
                 var root = document.documentElement;
                 var x = root.scrollLeft + e.clientX;    
                 var y = root.scrollTop + e.clientY;
                
                 if ( this.get_menu().clientWidth+e.clientX > root.clientWidth)
                {
                        x = x - this.get_menu().clientWidth;
                }
                 if ( this.get_menu().clientHeight+e.clientY > root.clientHeight)
                {
                        y = y - this.get_menu().clientHeight;
                }
                
                 this.get_menu().style.left = x + "px";    
                 this.get_menu().style.top = y + "px";    
                 this.get_menu().style.visibility = "visible";
                
                 this.set_handle( null);
                 this.set_menuItem( null);
                 this.set_target( null);
                
                 return false;
        },

        hidden: function()    
        {
                 if ( this.get_menu() != null)
                {
                         this.get_menu().style.visibility = "hidden";
                }
        }
}

if (document.all)
{
        window.attachEvent(' yy_sgv_rightMenu = new yy_sgv_rightMenu())
}
else
{
        window.addEventListener('load', yy_sgv_rightMenu = new yy_sgv_rightMenu(), false);
}

function yy_sgv_setRightMenu(handle, menuItem, target, cssClass)
{
/// <summary>设置需要显示的右键菜单</summary>

        yy_sgv_rightMenu.set_handle(handle);
        yy_sgv_rightMenu.set_menuItem(menuItem);
        yy_sgv_rightMenu.set_target(target);
        yy_sgv_rightMenu.set_cssClass(cssClass);
}
/*右键菜单 结束*/
 
css
/*右键菜单必须要具有的样式*/
.yy_sgv_rightMenuBase
{
        visibility
: hidden;
        position
: absolute;
}
/*右键菜单的示例样式 开始*/
.yy_sgv_rightMenu
{
        border-right
: 2px outset;
        border-top
: 2px outset;
        border-left
: 2px outset;
        border-bottom
: 2px outset;
        background-color
: buttonface;
}
.yy_sgv_rightMenu hr
{
        width
: 300px;
}
.yy_sgv_rightMenu ul
{
        list-style
: none; margin: 0; padding: 0;
}
.yy_sgv_rightMenu ul li
{
        vertical-align
: bottom;
}
.yy_sgv_rightMenu A
{ color: MenuText; text-decoration: none; display: block; width: 300px; text-align: center; line-height: 20px }     
.yy_sgv_rightMenu A:link
{ color: MenuText; text-decoration: none; }     
.yy_sgv_rightMenu A:active
{ color: MenuText; text-decoration: none; }     
.yy_sgv_rightMenu A:visited
{ color: MenuText; text-decoration: none; }     
.yy_sgv_rightMenu A:hover
{ color: HighlightText; background-color: Highlight; }
/*右键菜单的示例样式 结束*/
 
c#
InBlock.gif using System;
InBlock.gif using System.Collections.Generic;
InBlock.gif using System.Text;
InBlock.gif
InBlock.gif using System.Web.UI.WebControls;
InBlock.gif using System.Web.UI;
InBlock.gif
InBlock.gif namespace YYControls.SmartGridViewFunction
InBlock.gif{
InBlock.gif         /// <summary>
InBlock.gif         /// 扩展功能:给数据行增加右键菜单
InBlock.gif         /// </summary>
InBlock.gif         public class ContextMenuFunction : ExtendFunction
InBlock.gif        {
InBlock.gif                List< string> _rowRightClickButtonUniqueIdList = new List< string>();
InBlock.gif
InBlock.gif                 private string _menuItem;
InBlock.gif                 private string _target;
InBlock.gif
InBlock.gif                 /// <summary>
InBlock.gif                 /// 构造函数
InBlock.gif                 /// </summary>
InBlock.gif                 public ContextMenuFunction()
InBlock.gif                        : base()
InBlock.gif                {
InBlock.gif
InBlock.gif                }
InBlock.gif
InBlock.gif                 /// <summary>
InBlock.gif                 /// 构造函数
InBlock.gif                 /// </summary>
InBlock.gif                 /// <param name="sgv">SmartGridView对象</param>
InBlock.gif                 public ContextMenuFunction(SmartGridView sgv)
InBlock.gif                        : base(sgv)
InBlock.gif                {
InBlock.gif
InBlock.gif                }
InBlock.gif
InBlock.gif                 /// <summary>
InBlock.gif                 /// 扩展功能的实现
InBlock.gif                 /// </summary>
InBlock.gif                 protected override void Execute()
InBlock.gif                {
InBlock.gif                         this._sgv.RowDataBoundDataRow += new SmartGridView.RowDataBoundDataRowHandler(_sgv_RowDataBoundDataRow);
InBlock.gif                         this._sgv.PreRender += new EventHandler(_sgv_PreRender);
InBlock.gif                         this._sgv.RenderBegin += new SmartGridView.RenderBeginHandler(_sgv_RenderBegin);
InBlock.gif
InBlock.gif                         foreach (ContextMenu cm in this._sgv.ContextMenus)
InBlock.gif                        {
InBlock.gif                                 string text = cm.Text == null ? "" : cm.Text;
InBlock.gif                                 string target = cm.Target == null ? "" : cm.Target;
InBlock.gif
InBlock.gif                                 this._menuItem += String.Format( ",\"{0}\"", text.Replace( ",", ","));
InBlock.gif                                 this._target += String.Format( ",\"{0}\"", target.Replace( ",", ","));
InBlock.gif                        }
InBlock.gif
InBlock.gif                         this._menuItem = String.Format( "new Array({0})", this._menuItem.TrimStart(','));
InBlock.gif                         this._target = String.Format( "new Array({0})", this._target.TrimStart(','));
InBlock.gif                }
InBlock.gif
InBlock.gif                 void _sgv_RowDataBoundDataRow( object sender, GridViewRowEventArgs e)
InBlock.gif                {
InBlock.gif                         string handle = "";
InBlock.gif
InBlock.gif                         // 从用户定义的ContextMenus集合中分解出ContextMenu
InBlock.gif                         foreach (ContextMenu cm in this._sgv.ContextMenus)
InBlock.gif                        {
InBlock.gif                                 if (!String.IsNullOrEmpty(cm.NavigateUrl))
InBlock.gif                                {
InBlock.gif                                        handle += String.Format( ",\"{0}\"", cm.NavigateUrl);
InBlock.gif                                         continue;
InBlock.gif                                }
InBlock.gif                                 else if (String.IsNullOrEmpty(cm.BoundCommandName))
InBlock.gif                                {
InBlock.gif                                        handle += String.Format( ",\"{0}\"", "#");
InBlock.gif                                         continue;
InBlock.gif                                }
InBlock.gif
InBlock.gif                                 foreach (TableCell tc in e.Row.Cells)
InBlock.gif                                {
InBlock.gif                                         bool bln = false;
InBlock.gif
InBlock.gif                                         foreach (Control c in tc.Controls)
InBlock.gif                                        {
InBlock.gif                                                 // 如果控件继承自接口IButtonControl
InBlock.gif                                                 if (c is IButtonControl
InBlock.gif                                                        && ((IButtonControl)c).CommandName == cm.BoundCommandName)
InBlock.gif                                                {
InBlock.gif                                                        handle += String.Format( ",\"{0}\"", this._sgv.Page.ClientScript.GetPostBackClientHyperlink(c, ""));
InBlock.gif                                                        _rowRightClickButtonUniqueIdList.Add(c.UniqueID);
InBlock.gif
InBlock.gif                                                        bln = true;
InBlock.gif                                                         break;
InBlock.gif                                                }
InBlock.gif                                        }
InBlock.gif
InBlock.gif                                         if (bln)
InBlock.gif                                        {
InBlock.gif                                                 break;
InBlock.gif                                        }
InBlock.gif                                }
InBlock.gif                        }
InBlock.gif
InBlock.gif                        handle = String.Format( "new Array({0})", handle.TrimStart(','));
InBlock.gif
InBlock.gif                         string oncontextmenuValue =
InBlock.gif                                String.Format
InBlock.gif                                (
InBlock.gif                                         "yy_sgv_setRightMenu({0},{1}_rightMenuItem,{1}_rightMenuTarget, {2})",
InBlock.gif                                        handle,
InBlock.gif                                         this._sgv.ClientID,
InBlock.gif                                        String.IsNullOrEmpty( this._sgv.ContextMenuCssClass) ? "null" : "'" + this._sgv.ContextMenuCssClass + "'"
InBlock.gif                                );
InBlock.gif
InBlock.gif                         // 设置按钮的客户端属性
InBlock.gif                        YYControls.Helper.Common.SetAttribute(
InBlock.gif                                e.Row,
InBlock.gif                                 "oncontextmenu",
InBlock.gif                                oncontextmenuValue,
InBlock.gif                                AttributeValuePosition.Last);
InBlock.gif                }
InBlock.gif
InBlock.gif                 /// <summary>
InBlock.gif                 /// SmartGridView的PreRender事件
InBlock.gif                 /// </summary>
InBlock.gif                 /// <param name="sender"></param>
InBlock.gif                 /// <param name="e"></param>
InBlock.gif                 void _sgv_PreRender( object sender, EventArgs e)
InBlock.gif                {
InBlock.gif                         // 构造所需脚本
InBlock.gif                         string scriptString = "";
InBlock.gif                        scriptString += "document.οncοntextmenu=function(evt){return yy_sgv_rightMenu.show(evt);};";
InBlock.gif                        scriptString += "document.οnclick=function(){yy_sgv_rightMenu.hidden();};";
InBlock.gif
InBlock.gif                         // 注册所需脚本
InBlock.gif                         if (! this._sgv.Page.ClientScript.IsClientScriptBlockRegistered( "yy_sgv_rightMenu"))
InBlock.gif                        {
InBlock.gif                                 this._sgv.Page.ClientScript.RegisterClientScriptBlock
InBlock.gif                                (
InBlock.gif                                         this._sgv.GetType(),
InBlock.gif                                         "yy_sgv_rightMenu",
InBlock.gif                                        scriptString,
InBlock.gif                                         true
InBlock.gif                                );
InBlock.gif                        }
InBlock.gif
InBlock.gif                         // 为每个SmartGridView注册与右键菜单相关的变量
InBlock.gif                         if (! this._sgv.Page.ClientScript.IsClientScriptBlockRegistered(String.Format( "yy_sgv_rightMenu_{0}", this._sgv.ClientID)))
InBlock.gif                        {
InBlock.gif                                 this._sgv.Page.ClientScript.RegisterClientScriptBlock
InBlock.gif                                (
InBlock.gif                                         this._sgv.GetType(),
InBlock.gif                                        String.Format( "yy_sgv_rightMenu_{0}", this._sgv.ClientID),
InBlock.gif                                        String.Format(
InBlock.gif                                         "var {0}_rightMenuItem={1};var {0}_rightMenuTarget={2};",
InBlock.gif                                                 this._sgv.ClientID,
InBlock.gif                                                 this._menuItem,
InBlock.gif                                                 this._target),
InBlock.gif                                         true
InBlock.gif                                );
InBlock.gif                        }
InBlock.gif
InBlock.gif                }
InBlock.gif
InBlock.gif                 /// <summary>
InBlock.gif                 /// RenderBegin
InBlock.gif                 /// </summary>
InBlock.gif                 /// <param name="sender"></param>
InBlock.gif                 /// <param name="writer"></param>
InBlock.gif                 void _sgv_RenderBegin( object sender, HtmlTextWriter writer)
InBlock.gif                {
InBlock.gif                         foreach ( string uniqueId in this._rowRightClickButtonUniqueIdList)
InBlock.gif                        {
InBlock.gif                                 // 注册回发或回调数据以进行验证
InBlock.gif                                 this._sgv.Page.ClientScript.RegisterForEventValidation(uniqueId);
InBlock.gif                        }
InBlock.gif                }
InBlock.gif
InBlock.gif        }
InBlock.gif}
 
InBlock.gif /*正式版的实现 结束*/
 
InBlock.gif /*测试版的实现 开始*/
 
介绍
给GridView的数据行增加右键菜单可以增加用户体验,不过实现起来挺麻烦的,现在我们扩展一下GridView控件以实现这样的功能。


控件开发
1、新建一个继承自GridView的类。
/// <summary>
/// 继承自GridView
/// </summary>
InBlock.gif[ToolboxData( @"<{0}:SmartGridView runat='server'></{0}:SmartGridView>")]
InBlock.gif public class SmartGridView : GridView
InBlock.gif{
InBlock.gif}