扩展GridView控件——给数据行增加右键菜单

GridView既强大又好用。为了让它更强大、更好用,我们来写一个继承自GridView的控件。
[源码下载]
http://files.cnblogs.com/webabcd/yycontrols.rar

介绍
给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;

        strShow = 
"" <div id='rightmenu' style='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> "" ;
        
        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 
+=   "" onmouseout = "" changeStyle( this ' out ' ); ""   "" ;

            
if  ( this .type  ==   ' Command ' )
            {
                
//  右键菜单是按钮类型,调用所对应的按钮的click事件
                strShow  +=   "" onclick = "" 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 
+=   "" onclick = """" ;
                    strShow 
+=   this .target;
                    strShow 
+=   "" .location = ' "";
                    strShow += this.url;
                    strShow += ""
'"" ;
                }
                
else
                {
                    strShow 
+=   "" onclick = "" 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;
    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)
    {
        
//  给数据行增加客户端代码
        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 >  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值