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

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


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


作者: webabcd


/* 正式版的实现 开始 */

介绍
扩展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.onmousedown = 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('onload', 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#
using System;
using System.Collections.Generic;
using System.Text;

using System.Web.UI.WebControls;
using System.Web.UI;

namespace YYControls.SmartGridViewFunction
{
    /// <summary>
    
/// 扩展功能:给数据行增加右键菜单
    
/// </summary>
    public class ContextMenuFunction : ExtendFunction
    {
        List<string> _rowRightClickButtonUniqueIdList = new List<string>();

        private string _menuItem;
        private string _target;

        /// <summary>
        
/// 构造函数
        
/// </summary>
        public ContextMenuFunction()
            : base()
        {

        }

        /// <summary>
        
/// 构造函数
        
/// </summary>
        
/// <param name="sgv">SmartGridView对象</param>
        public ContextMenuFunction(SmartGridView sgv)
            : base(sgv)
        {

        }

        /// <summary>
        
/// 扩展功能的实现
        
/// </summary>
        protected override void Execute()
        {
            this._sgv.RowDataBoundDataRow += new SmartGridView.RowDataBoundDataRowHandler(_sgv_RowDataBoundDataRow);
            this._sgv.PreRender += new EventHandler(_sgv_PreRender);
            this._sgv.RenderBegin += new SmartGridView.RenderBeginHandler(_sgv_RenderBegin);

            foreach (ContextMenu cm in this._sgv.ContextMenus)
            {
                string text = cm.Text == null ? "" : cm.Text;
                string target = cm.Target == null ? "" : cm.Target;

                this._menuItem += String.Format(",\"{0}\"", text.Replace(",", ","));
                this._target += String.Format(",\"{0}\"", target.Replace(",", ","));
            }

            this._menuItem = String.Format("new Array({0})", this._menuItem.TrimStart(','));
            this._target = String.Format("new Array({0})", this._target.TrimStart(','));
        }

        void _sgv_RowDataBoundDataRow(object sender, GridViewRowEventArgs e)
        {
            string handle = "";

            // 从用户定义的ContextMenus集合中分解出ContextMenu
            foreach (ContextMenu cm in this._sgv.ContextMenus)
            {
                if (!String.IsNullOrEmpty(cm.NavigateUrl))
                {
                    handle += String.Format(",\"{0}\"", cm.NavigateUrl);
                    continue;
                }
                else if (String.IsNullOrEmpty(cm.BoundCommandName))
                {
                    handle += String.Format(",\"{0}\"", "#");
                    continue;
                }

                foreach (TableCell tc in e.Row.Cells)
                {
                    bool bln = false;

                    foreach (Control c in tc.Controls)
                    {
                        // 如果控件继承自接口IButtonControl
                        if (c is IButtonControl
                            && ((IButtonControl)c).CommandName == cm.BoundCommandName)
                        {
                            handle += String.Format(",\"{0}\"", this._sgv.Page.ClientScript.GetPostBackClientHyperlink(c, ""));
                            _rowRightClickButtonUniqueIdList.Add(c.UniqueID);

                            bln = true;
                            break;
                        }
                    }

                    if (bln)
                    {
                        break;
                    }
                }
            }

            handle = String.Format("new Array({0})", handle.TrimStart(','));

            string oncontextmenuValue =
                String.Format
                (
                    "yy_sgv_setRightMenu({0},{1}_rightMenuItem,{1}_rightMenuTarget, {2})",
                    handle,
                    this._sgv.ClientID,
                    String.IsNullOrEmpty(this._sgv.ContextMenuCssClass) ? "null" : "'" + this._sgv.ContextMenuCssClass + "'"
                );

            // 设置按钮的客户端属性
            YYControls.Helper.Common.SetAttribute(
                e.Row,
                "oncontextmenu",
                oncontextmenuValue,
                AttributeValuePosition.Last);
        }

        /// <summary>
        
/// SmartGridView的PreRender事件
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        void _sgv_PreRender(object sender, EventArgs e)
        {
            // 构造所需脚本
            string scriptString = "";
            scriptString += "document.οncοntextmenu=function(evt){return yy_sgv_rightMenu.show(evt);};";
            scriptString += "document.οnclick=function(){yy_sgv_rightMenu.hidden();};";

            // 注册所需脚本
            if (!this._sgv.Page.ClientScript.IsClientScriptBlockRegistered("yy_sgv_rightMenu"))
            {
                this._sgv.Page.ClientScript.RegisterClientScriptBlock
                (
                    this._sgv.GetType(),
                    "yy_sgv_rightMenu",
                    scriptString,
                    true
                );
            }

            // 为每个SmartGridView注册与右键菜单相关的变量
            if (!this._sgv.Page.ClientScript.IsClientScriptBlockRegistered(String.Format("yy_sgv_rightMenu_{0}", this._sgv.ClientID)))
            {
                this._sgv.Page.ClientScript.RegisterClientScriptBlock
                (
                    this._sgv.GetType(),
                    String.Format("yy_sgv_rightMenu_{0}", this._sgv.ClientID),
                    String.Format(
                    "var {0}_rightMenuItem={1};var {0}_rightMenuTarget={2};",
                        this._sgv.ClientID,
                        this._menuItem,
                        this._target),
                    true
                );
            }

        }

        /// <summary>
        
/// RenderBegin
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="writer"></param>
        void _sgv_RenderBegin(object sender, HtmlTextWriter writer)
        {
            foreach (string uniqueId in this._rowRightClickButtonUniqueIdList)
            {
                // 注册回发或回调数据以进行验证
                this._sgv.Page.ClientScript.RegisterForEventValidation(uniqueId);
            }
        }

    }
}

/* 正式版的实现 结束 */


/* 测试版的实现 开始 */

介绍
给GridView的数据行增加右键菜单可以增加用户体验,不过实现起来挺麻烦的,现在我们扩展一下GridView控件以实现这样的功能。


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

2、新建一个ContextMenu实体类,有六个属性
using System;
using System.Collections.Generic;
using System.Text;

using System.ComponentModel;
using System.Web.UI;

namespace YYControls.SmartGridView
{
    /// <summary>
    
/// ContextMenu 的摘要说明。
    
/// </summary>
    [ToolboxItem(false)]
    public class ContextMenu
    {
        private string _icon;
        /// <summary>
        
/// 文字左边的图标的链接
        
/// </summary>
        public string Icon
        {
            get { return _icon; }
            set { _icon = value; }
        }

        private string _text;
        /// <summary>
        
/// 菜单的文字
        
/// </summary>
        public string Text
        {
            get { return _text; }
            set { _text = value; }
        }
       
        private string _commandButtonId;
        /// <summary>
        
/// 所调用的命令按钮的ID
        
/// </summary>
        public string CommandButtonId
        {
            get { return _commandButtonId; }
            set { _commandButtonId = value; }
        }

        private string _navigateUrl;
        /// <summary>
        
/// 链接的url
        
/// </summary>
        public string NavigateUrl
        {
            get { return _navigateUrl; }
            set { _navigateUrl = value; }
        }

        private ItemTypeCollection _itemType;
        /// <summary>
        
/// 右键菜单的项的类别
        
/// </summary>
        public ItemTypeCollection ItemType
        {
            get { return _itemType; }
            set { _itemType = value; }
        }

        private TargetCollection _target;
        /// <summary>
        
/// 链接的target
        
/// </summary>
        public TargetCollection Target
        {
            get { return _target; }
            set { _target = value; }
        }


        /// <summary>
        
/// 右键菜单的项的类别
        
/// </summary>
        public enum ItemTypeCollection
        {
            /// <summary>
            
/// 链接
            
/// </summary>
            Link,
            /// <summary>
            
/// 按钮
            
/// </summary>
            Command,
            /// <summary>
            
/// 分隔线
            
/// </summary>
            Separator
        }

        /// <summary>
        
/// 链接的target
        
/// </summary>
        public enum TargetCollection
        {
            /// <summary>
            
/// 新开窗口
            
/// </summary>
            Blank,
            /// <summary>
            
/// 当前窗口
            
/// </summary>
            Self,
            /// <summary>
            
/// 跳出框架
            
/// </summary>
            Top
        }
    }
}

3、新建一个继承自CollectionBase的类ContextMenus
using System.Collections;
using System.ComponentModel;
using System.Web.UI;

namespace YYControls.SmartGridView
{
    /// <summary>
    
/// ContextMenus 的摘要说明。
    
/// 注意要继承自CollectionBase
    
/// </summary>
    [
    ToolboxItem(false),
    ParseChildren(true)
    ]
    public class ContextMenus : CollectionBase
    {
        /// <summary>
        
/// 构造函数
        
/// </summary>
        public ContextMenus()
            : base()
        {
        }

        /// <summary>
        
/// 实现IList接口
        
/// 获取或设置指定索引处的元素。
        
/// </summary>
        
/// <param name="index">要获得或设置的元素从零开始的索引</param>
        
/// <returns></returns>
        public ContextMenu this[int index]
        {
            get
            {
                return (ContextMenu)base.List[index];
            }
            set
            {
                base.List[index] = (ContextMenu)value;
            }
        }

        /// <summary>
        
/// 实现IList接口
        
/// 将某项添加到 System.Collections.IList 中。
        
/// </summary>
        
/// <param name="item">要添加到 System.Collections.IList 的 System.Object。</param>
        public void Add(ContextMenu item)
        {
            base.List.Add(item);
        }

        /// <summary>
        
/// 实现IList接口
        
/// 从 System.Collections.IList 中移除特定对象的第一个匹配项。
        
/// </summary>
        
/// <param name="index">要从 System.Collections.IList 移除的 System.Object</param>
        public void Remove(int index)
        {
            if (index > -1 && index < base.Count)
            {
                base.List.RemoveAt(index);
            }
        }

        /// <summary>
        
/// ToString()
        
/// </summary>
        
/// <returns></returns>
        public override string ToString()
        {
            return "ContextMenus";
        }
    }
}

4、在继承自GridView的类中加一个复杂对象属性,该复杂对象就是第3步创建的那个ContextMenus
         private ContextMenus _contextMenus;
         /// <summary>
        
/// 行的右键菜单集合
        
/// </summary>
        [
        PersistenceMode(PersistenceMode.InnerProperty),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        Description("行的右键菜单"),
        Category("扩展")
        ]
         public  virtual ContextMenus ContextMenus
         {
            get
            {
                if (_contextMenus == null)
                {
                    _contextMenus = new ContextMenus();
                }
                return _contextMenus;
            }
        }

5、新建一个JavaScriptConstant类,把我们要用到的javascript存在一个常量里
using System;
using System.Collections.Generic;
using System.Text;

namespace YYControls.SmartGridView
{
    /// <summary>
    
/// javascript
    
/// </summary>
    public class JavaScriptConstant
    {
        internal const string jsContextMenu = @"<script type=""text/javascript"">
        //<![CDATA[
        // 数据行的ClientId
        var _rowClientId = '';

        // 以下实现右键菜单,网上找的,不知道原创是谁
        function contextMenu()
        {
            this.items = new Array();
            this.addItem = function (item)
            {
                this.items[this.items.length] = item;
            }

            this.show = function (oDoc)
            {
                var strShow = '';
                var i;

                // 加上word-break: keep-all; 防止菜单项换行
                strShow = ""<div id='rightmenu' style='word-break: keep-all;BACKGROUND-COLOR: #ffffff; BORDER: #000000 1px solid; LEFT: 0px; POSITION: absolute; TOP: 0px; VISIBILITY: hidden; Z-INDEX: 10'>"";
                strShow += ""<table border='0' height='"";
                strShow += this.items.length * 20;
                strShow += ""' cellpadding='0' cellspacing='0'>"";
                strShow += ""<tr height='3'><td bgcolor='#d0d0ce' width='2'></td><td>"";
                strShow += ""<table border='0' width='100%' height='100%' cellpadding=0 cellspacing=0 bgcolor='#ffffff'>"";
                strShow += ""<tr><td bgcolor='#d0d0ce' width='23'></td><td><img src=' ' height='1' border='0'></td></tr></table>"";
                strShow += ""</td><td width='2'></td></tr>"";
                strShow += ""<tr><td bgcolor='#d0d0ce'></td><td>"";
                strShow += ""<table border='0' width='100%' height='100%' cellpadding=3 cellspacing=0 bgcolor='#ffffff'>"";
                
                oDoc.write(strShow);

                for(i=0; i<this.items.length; i++)
                {
                    this.items[i].show(oDoc);
                }
                
                strShow = ""</table></td><td></td></tr>"";
                strShow += ""<tr height='3'><td bgcolor='#d0d0ce'></td><td>"";
                strShow += ""<table border='0' width='100%' height='100%' cellpadding=0 cellspacing=0 bgcolor='#ffffff'>"";
                strShow += ""<tr><td bgcolor='#d0d0ce' width='23'></td><td><img src=' ' height='1' border='0'></td></tr></table>"";
                strShow += ""</td><td></td></tr>"";
                strShow += ""</table></div>\n"";
                
                oDoc.write(strShow);
            }
        }

        function contextItem(text, icon, cmd, url, target, type)
        {
            this.text = text ? text : '';
            this.icon = icon ? icon : '';
            this.cmd = cmd ? cmd : '';
            this.url = url ? url : '';
            this.target =target ? target : '';
            this.type = type ? type : 'Link';


            this.show = function (oDoc)
            {
                var strShow = '';

                if(this.type == 'Link' || this.type == 'Command')
                {
                    strShow += ""<tr "";
                    strShow += ""οnmοuseοver=\""changeStyle(this, 'on');\"" "";
                    strShow += ""οnmοuseοut=\""changeStyle(this, 'out');\"" "";

                    if (this.type == 'Command')
                    {
                        // 右键菜单是按钮类型,调用所对应的按钮的click事件
                        strShow += ""οnclick=\""document.getElementById("";
                        strShow += ""_rowClientId + "";
                        strShow += ""'_"";
                        strShow += this.cmd;
                        strShow += ""').click()"";
                    }
                    else
                    {
                        // 右键菜单是链接类型
                        if (this.target == 'Top') this.target = 'top';
                        if (this.target == 'Self') this.target = 'self';

                        if (this.target == 'top' || this.target == 'self')
                        {
                            strShow += ""οnclick=\"""";
                            strShow += this.target;
                            strShow += "".location='"";
                            strShow += this.url;
                            strShow += ""'"";
                        }
                        else
                        {
                            strShow += ""οnclick=\""window.open('"";
                            strShow += this.url;
                            strShow += ""')"";
                        }
                    }   
                    strShow += ""\"">"";
                    strShow += ""<td class='ltdexit' width='16'>"";

                    if (this.icon == '')
                    {
                        strShow += '&nbsp;';
                    }
                    else 
                    {
                        strShow += ""<img border='0' src='"";
                        strShow += this.icon;
                        strShow += ""' width='16' height='16' style='POSITION: relative'></img>"";
                    }

                    strShow += ""</td><td class='mtdexit'>"";
                    strShow += this.text;
                    strShow += ""</td><td class='rtdexit' width='5'>&nbsp;</td></tr>"";
                }
                // 右键菜单是分隔线
                else if (this.type == 'Separator')
                {
                    strShow += ""<tr><td class='ltdexit'>&nbsp;</td>"";
                    strShow += ""<td class='mtdexit' colspan='2'><hr color='#000000' size='1'></td></tr>"";
                }

                oDoc.write(strShow);
            }
        }

        function changeStyle(obj, cmd)
        { 
            if(obj)
            {
                try 
                {
                    var imgObj = obj.children(0).children(0);

                    if(cmd == 'on') 
                    {
                        obj.children(0).className = 'ltdfocus';
                        obj.children(1).className = 'mtdfocus';
                        obj.children(2).className = 'rtdfocus';
                        
                        if(imgObj)
                        {
                            if(imgObj.tagName.toUpperCase() == 'IMG')
                            {
                                imgObj.style.left = '-1px';
                                imgObj.style.top = '-1px';
                            }
                        }
                    }
                    else if(cmd == 'out') 
                    {
                        obj.children(0).className = 'ltdexit';
                        obj.children(1).className = 'mtdexit';
                        obj.children(2).className = 'rtdexit';

                        if(imgObj)
                        {
                            if(imgObj.tagName.toUpperCase() == 'IMG')
                            {
                                imgObj.style.left = '0px';
                                imgObj.style.top = '0px';
                            }
                        }
                    }
                }
                catch (e) {}
            }
        }

        function showMenu(rowClientId)
        {
            _rowClientId = rowClientId;

            var x, y, w, h, ox, oy;

            x = event.clientX;
            y = event.clientY;

            var obj = document.getElementById('rightmenu');

            if (obj == null)
                return true;

            ox = document.body.clientWidth;
            oy = document.body.clientHeight;

            if(x > ox || y > oy)
                return false;

            w = obj.offsetWidth;
            h = obj.offsetHeight;

            if((x + w) > ox)
                x = x - w;

            if((y + h) > oy)
                y = y - h;

         
            // obj.style.posLeft = x + document.body.scrollLeft;
            // obj.style.posTop = y + document.body.scrollTop;
            // xhtml不支持上面的了
            // 就是说如果你的页头声明了页是xhtml的话就不能用上面那句了,vs2005创建的aspx会默认加上xhtml声明
            // 此时应该用如下的方法
            obj.style.posLeft = x + document.documentElement.scrollLeft;
            obj.style.posTop = y + document.documentElement.scrollTop;

            obj.style.visibility = 'visible';

            return false;
        }

        function hideMenu()
        {
            if(event.button == 0)
            {
                var obj = document.getElementById('rightmenu');
                if (obj == null)
                    return true;

                obj.style.visibility = 'hidden';
                obj.style.posLeft = 0;
                obj.style.posTop = 0;
            }
        }

        function writeStyle()
        {
            var strStyle = '';

            strStyle += ""<STYLE type='text/css'>"";
            strStyle += ""TABLE {Font-FAMILY: 'Tahoma','Verdana','宋体'; FONT-SIZE: 9pt}"";
            strStyle += "".mtdfocus {BACKGROUND-COLOR: #ccccff; BORDER-BOTTOM: #000000 1px solid; BORDER-TOP: #000000 1px solid; CURSOR: hand}"";
            strStyle += "".mtdexit {BACKGROUND-COLOR: #ffffff; BORDER-BOTTOM: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid}"";
            strStyle += "".ltdfocus {BACKGROUND-COLOR: #ccccff; BORDER-BOTTOM: #000000 1px solid; BORDER-TOP: #000000 1px solid; BORDER-LEFT: #000000 1px solid; CURSOR: hand}"";
            strStyle += "".ltdexit {BACKGROUND-COLOR: #d0d0ce; BORDER-BOTTOM: #d0d0ce 1px solid; BORDER-TOP: #d0d0ce 1px solid; BORDER-LEFT: #d0d0ce 1px solid}"";
            strStyle += "".rtdfocus {BACKGROUND-COLOR: #ccccff; BORDER-BOTTOM: #000000 1px solid; BORDER-TOP: #000000 1px solid; BORDER-RIGHT: #000000 1px solid; CURSOR: hand}"";
            strStyle += "".rtdexit {BACKGROUND-COLOR: #ffffff; BORDER-BOTTOM: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid}"";
            strStyle += ""</STYLE>"";

            document.write(strStyle);
        }

        function makeMenu()
        {
            var myMenu, item;

            myMenu = new contextMenu();

            // 增加右键菜单项 开始
            // item = new contextItem("", "", "", "", "", "");
            // 1-菜单项的文本
            // 2-图标链接
            // 3-所调用的命令按钮的ID
            // 4-链接地址
            // 5-链接的target
            // 6-右键菜单的项的类别
            // myMenu.addItem(item);

            [$MakeMenu$]
            // 增加右键菜单项 结束

            myMenu.show(this.document);

            delete item;

            delete myMenu;
        }

        function toggleMenu(isEnable)
        {
            if(isEnable)
                document.oncontextmenu = showMenu;
            else
                document.oncontextmenu = new function() {return true;};
        }

        writeStyle();

        makeMenu();

        document.onclick = hideMenu;
        //]]>
        </script>";
    }
}

6、重写OnPreRender方法,注册上面那段客户端脚本
         /// <summary>
        
/// OnPreRender
        
/// </summary>
        
/// <param name="e"></param>
         protected  override  void OnPreRender(EventArgs e)
         {
            if (ContextMenus.Count > 0)
            {
                StringBuilder sb = new StringBuilder();
                foreach (ContextMenu cm in ContextMenus)
                {
                    // item = new contextItem("", "", "", "", "", "");
                    
// 1-菜单项的文本
                    
// 2-图标链接
                    
// 3-所调用的命令按钮的ID
                    
// 4-链接地址
                    
// 5-链接的target
                    
// 6-右键菜单的项的类别

                    
// 命令按钮
                    if (cm.ItemType == ContextMenu.ItemTypeCollection.Command)
                    {
                        sb.Append("item = new contextItem(\"" + cm.Text +
                            "\", \"" + ResolveUrl(cm.Icon) + "\", \"" +
                            cm.CommandButtonId + "\", \"\", \"\", \"Command\");");
                    }
                    // 链接
                    else if (cm.ItemType == ContextMenu.ItemTypeCollection.Link)
                    {
                        sb.Append("item = new contextItem(\"" + cm.Text +
                            "\", \"" + ResolveUrl(cm.Icon) + "\", \"\", \"" +
                            cm.NavigateUrl + "\", \"" +
                            cm.Target + "\", \"Link\");");
                    }
                    // 分隔线
                    else if (cm.ItemType == ContextMenu.ItemTypeCollection.Separator)
                    {
                        sb.Append("item = new contextItem(\"\", \"\", \"\", \"\", \"\", \"Separator\");");
                    }

                    sb.Append("myMenu.addItem(item);");
                }

                // 注册客户端代码
                if (!Page.ClientScript.IsClientScriptBlockRegistered("jsContextMenu"))
                {
                    Page.ClientScript.RegisterClientScriptBlock(
                        this.GetType(),
                        "jsContextMenu", JavaScriptConstant.jsContextMenu.Replace("[$MakeMenu$]", sb.ToString())
                        );
                }
            }

            base.OnPreRender(e);
        }

7、重写OnRowDataBound给数据行增加客户端代码以调用我们注册的那段javascript,从而实现给GridView的数据行增加右键菜单的功能。
         /// <summary>
        
/// OnRowDataBound
        
/// </summary>
        
/// <param name="e"></param>
         protected  override  void OnRowDataBound(GridViewRowEventArgs e)
         {
            if (e.Row.RowType == DataControlRowType.DataRow)
            {
                if (ContextMenus.Count > 0)
                {
                    // 给数据行增加客户端代码
                    e.Row.Attributes.Add("oncontextmenu", "showMenu('" + e.Row.ClientID + "');return false;");
                }
            }

            base.OnRowDataBound(e);
        }


控件使用
添加这个控件到工具箱里,然后拖拽到webform上,设置如下属性:ItemType为右键菜单的项的类别(Link,Command,Separator);Icon为文字左边的图标的链接;Text为菜单的文字;CommandButtonId为所调用的命令按钮的ID;NavigateUrl为链接的url;Target为链接的target(Blank,Self,Top)
ObjData.cs
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

using System.ComponentModel;

/// <summary>
/// OjbData 的摘要说明
/// </summary>
public  class OjbData
{
    public OjbData()
    {
        //
        
// TODO: 在此处添加构造函数逻辑
        
//
    }

    [DataObjectMethod(DataObjectMethodType.Select, true)]
    public DataTable Select()
    {
        DataTable dt = new DataTable();
        dt.Columns.Add("no", typeof(string));
        dt.Columns.Add("name", typeof(string));

        for (int i = 0; i < 30; i++)
        {
            DataRow dr = dt.NewRow();
            dr[0] = "no" + i.ToString().PadLeft(2, '0');
            dr[1] = "name" + i.ToString().PadLeft(2, '0');

            dt.Rows.Add(dr);
        }

        return dt;
    }
}

Default.aspx
<% @ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default"  %>

<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
< html  xmlns ="http://www.w3.org/1999/xhtml" >
< head  runat ="server" >
     < title >SmartGridView测试 </ title >
</ head >
< body >
     < form  id ="form1"  runat ="server" >
         < div >
             < yyc:SmartGridView  ID ="SmartGridView1"  runat ="server"  DataSourceID ="ObjectDataSource1"
                AutoGenerateColumns
="false" >
                 < Columns >
                     < asp:BoundField  DataField ="no"  HeaderText ="序号"  SortExpression ="no"  ItemStyle-Width ="100px"   />
                     < asp:BoundField  DataField ="name"  HeaderText ="名称"  SortExpression ="name"  ItemStyle-Width ="100px"   />
                     < asp:BoundField  DataField ="no"  HeaderText ="序号"  SortExpression ="no"  ItemStyle-Width ="100px"   />
                     < asp:BoundField  DataField ="name"  HeaderText ="名称"  SortExpression ="name"  ItemStyle-Width ="100px"   />
                     < asp:BoundField  DataField ="no"  HeaderText ="序号"  SortExpression ="no"  ItemStyle-Width ="100px"   />
                     < asp:BoundField  DataField ="name"  HeaderText ="名称"  SortExpression ="name"  ItemStyle-Width ="100px"   />
                     < asp:TemplateField >
                         < footerstyle  cssclass ="hidden"   />
                         < headerstyle  cssclass ="hidden"   />
                         < itemstyle  cssclass ="hidden"   />
                         < itemtemplate >
                     < asp:Button  id ="btnRightMenuButton"  runat ="server"  CommandName ="RightMenuButton"  CommandArgument ='<%#  Container.DataItemIndex % >' />
                 </ itemtemplate >
                     </ asp:TemplateField >
                 </ Columns >
                 < ContextMenus >
                     < yyc:ContextMenu  ItemType ="Command"  Text ="右键菜单按钮测试"  Icon ="~/Images/button.gif"  CommandButtonId ="btnRightMenuButton"   />
                     < yyc:ContextMenu  ItemType ="Separator"   />
                     < yyc:ContextMenu  ItemType ="Link"  Text ="控件源代码"  Icon ="~/Images/button.gif"  NavigateUrl ="http://webabcd.cnblogs.com"
                        Target
="Blank"   />
                 </ ContextMenus >
             </ yyc:SmartGridView >
             < asp:ObjectDataSource  ID ="ObjectDataSource1"  runat ="server"  SelectMethod ="Select"
                TypeName
="OjbData" ></ asp:ObjectDataSource >
         </ div >
     </ form >
</ body >
</ html >

注:如果想修改右键菜单的样式,请自行修改javascript,我就不把他们弄出来了。

/* 测试版的实现 结束 */


OK
[源码下载]  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值