当前位置:首页 > 扩展GridView控件(九)——给数据行增加右键菜单

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

点击次数:1495  更新日期:2010-12-27
\n

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


\n

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


\n

控件开发
1、新建一个继承自GridView的类。
复制C#代码保存代码/// <summary>
/// 继承自GridView
/// </summary>
[ToolboxData(@"<{0}:SmartGridView runat=\'server\'></{0}:SmartGridView>")]
public class SmartGridView : GridView
{
}
2、新建一个ContextMenu实体类,有六个属性
复制C#代码保存代码using System;
using System.Collections.Generic;
using System.Text;


\n

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


\n

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; }
}


\n

private string _text;
/// <summary>
/// 菜单的文字
/// </summary>
public string Text
{
get { return _text; }
set { _text = value; }
}


\n

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


\n

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


\n

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


\n

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


\n


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


\n

/// <summary>
/// 链接的target
/// </summary>
public enum TargetCollection
{
/// <summary>
/// 新开窗口
/// </summary>
Blank,
/// <summary>
/// 当前窗口
/// </summary>
Self,
/// <summary>
/// 跳出框架
/// </summary>
Top
}
}
}
3、新建一个继承自CollectionBase的类ContextMenus
复制C#代码保存代码using System.Collections;
using System.ComponentModel;
using System.Web.UI;


\n

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


\n

/// <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;
}
}


\n

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


\n

/// <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);
}
}


\n


/// <summary>
/// ToString()
/// </summary>
/// <returns></returns>
public override string ToString()
{
return “ContextMenus”;
}
}
}
4、在继承自GridView的类中加一个复杂对象属性,该复杂对象就是第3步创建的那个ContextMenus
复制C#代码保存代码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存在一个常量里
复制C#代码保存代码using System;
using System.Collections.Generic;
using System.Text;


\n

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


\n

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


\n

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


\n

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);


\n

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);
}
}


\n

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’;


\n


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


\n

if(this.type == ‘Link’ || this.type == ‘Command’)
{
strShow += “”<tr “”;
strShow += “”onmouseover=\\”"changeStyle(this, ‘on’);\\”" “”;
strShow += “”onmouseout=\\”"changeStyle(this, ‘out’);\\”" “”;


\n

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’;


\n

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′>”";


\n

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


\n

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>”";
}


\n

oDoc.write(strShow);
}
}


\n

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


\n

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’;


\n

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


\n

function showMenu(rowClientId)
{
_rowClientId = rowClientId;


\n

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


\n

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


\n

var obj = document.getElementById(‘rightmenu’);


\n

if (obj == null)
return true;


\n

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


\n

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


\n

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


\n

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


\n

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


\n


obj.style.posLeft = x + document.body.scrollLeft;
obj.style.posTop = y + document.body.scrollTop;
obj.style.visibility = ‘visible’;


\n

return false;
}


\n

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


\n

obj.style.visibility = ‘hidden’;
obj.style.posLeft = 0;
obj.style.posTop = 0;
}
}


\n

function writeStyle()
{
var strStyle = ”;


\n

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>”";


\n

document.write(strStyle);
}


\n

function makeMenu()
{
var myMenu, item;


\n

myMenu = new contextMenu();


\n

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


\n

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


\n

myMenu.show(this.document);


\n

delete item;


\n

delete myMenu;
}


\n

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


\n

writeStyle();


\n

makeMenu();


\n

document.onclick = hideMenu;
//]]>
</script>”;
}
}
6、重写OnPreRender方法,注册上面那段客户端脚本
复制C#代码保存代码/// <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-右键菜单的项的类别


\n

// 命令按钮
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\\”);”);
}


\n

sb.Append(“myMenu.addItem(item);”);
}


\n

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


\n

base.OnPreRender(e);
}
7、重写OnRowDataBound给数据行增加客户端代码以调用我们注册的那段javascript,从而实现给GridView的数据行增加右键菜单的功能
复制C#代码保存代码/// <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;”);
}


\n

base.OnRowDataBound(e);
}


\n

控件使用
添加这个控件到工具箱里,然后拖拽到webform上,设置如下属性:ItemType为右键菜单的项的类别(Link,Command,Separator);Icon为文字左边的图标的链接;Text为菜单的文字;CommandButtonId为所调用的命令按钮的ID;NavigateUrl为链接的url;Target为链接的target(Blank,Self,Top)
ObjData.cs
复制C#代码保存代码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;


\n

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


\n

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


\n

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′);


\n

dt.Rows.Add(dr);
}


\n

return dt;
}
}
Default.aspx
复制ASPX代码保存代码<%@ Page Language=”C#” AutoEventWireup=”true” CodeFile=”Default.aspx.cs” Inherits=”_Default” %>


\n

<!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><%@ Page Language=”C#” AutoEventWireup=”true” CodeFile=”Default.aspx.cs” Inherits=”_Default” %>


\n

<!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,我就不把他们弄出来了。


\n

转自【webabcd-.NET】

\n