支持行单击、双击事件的GridView和DataList控件(译)
2016-03-22 20:36
429 查看
支持行单击、双击事件的GridView和DataList控件(译)
让GridView和 DataList控件响应鼠标单击、双击事件。并且,使用 ClientScript.RegisterForEventValidation来注册相关事件避免禁用事件验证。介绍
网上有不少关于实现GridView行单击、双击事件的代码。但是我还没见过可以同时处理这两个事件和解决ASP.NET 2.0中事件验证错误的代码。在这里,我将描述如何在GridView,DataList和ListBox控件中处理单击、 双击。我还将展示如何处理事件验证而无需禁用它。
背景
在开发新的ASP.NET 应用程序以替换旧的 Windows 应用程序时,我被要求保持和原来差不多的用户体验。原来的程序可以让用户选择某行,并在该行的工具栏上执行一个操作。通过双击某行用户可以打开一个有该行详细信息的窗口。这类功能可以很容易的通过在GridView的每行添加两个按钮来实现,但我不希望这样。GridView中的单击和双击
创建一个包含默认页的web应用程序。然后,在页面的Page指令中添加EnableEventValidation="false"。稍后我们会将其删除。添加 GridView并绑定一些数据。添加两个使用 GridView编辑列选项的asp: ButtonField 控件。给这两个ButtonField的CommandName分别命名为SingleClick、DoubleClick。(选择按钮也可以用于 SingleClick事件但我已经决定两个都用 asp: ButtonField)。<Columns> <asp:ButtonFieldText="SingleClick" CommandName="SingleClick" /> <asp:ButtonFieldText="DoubleClick" CommandName="DoubleClick" /> </Columns>
创建一个RowCommand事件并且用 switch来分别捕获单击、双击事件。
在本例中,代码将返回被触发的事件。SingleClick命令还将修改GridView的SelectedIndex。
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e) { GridView_gridView = (GridView)sender; // Get the selected index and the command name int _selectedIndex = int.Parse(e.CommandArgument.ToString()); string _commandName = e.CommandName; switch(_commandName) { case ("SingleClick"): _gridView.SelectedIndex= _selectedIndex; this.Message.Text += "Single clicked GridViewrow at index " + _selectedIndex.ToString() + "<br />"; break; case ("DoubleClick"): this.Message.Text += "Double clicked GridViewrow at index " + _selectedIndex.ToString() + "<br />"; break; } }
创建一个RowDataBound事件去修改绑定的每一行。现在,我们需要得到 SingleClick按钮用于回发的客户端脚本并将其分配到整行。
if (e.Row.RowType == DataControlRowType.DataRow) { // Get the LinkButton control in the first cell LinkButton _singleClickButton = (LinkButton)e.Row.Cells[0].Controls[0]; // Get the javascript which is assigned to this LinkButton string _jsSingle = ClientScript.GetPostBackClientHyperlink(_singleClickButton, ""); // Add this javascript to the onclickAttribute of the row e.Row.Attributes["onclick"] = _jsSingle; }
当然我们也可以这样设置双击按钮,只是这样两个事件将不能同时工作。
if (e.Row.RowType == DataControlRowType.DataRow) { // Get the LinkButton control in the second cell LinkButton _doubleClickButton = (LinkButton)e.Row.Cells[1].Controls[0]; // Get the javascript which is assigned to this LinkButton string _jsDouble = ClientScript.GetPostBackClientHyperlink(_doubleClickButton, ""); // Add this JavaScript to the ondblclick Attribute of the row e.Row.Attributes["ondblclick"] = _jsDouble; }
如果我们同时实现了上面两个事件,在功能上只会响应单击事件。这是因为当用户双击时,他的第一次点击被识别为单击然后页面在双击事件响应前就回传了。JavaScript的setTimeOut方法可以用来给单击事件设置一个延迟,从而给用户一个机会去完成双击操作。通过查看页面源码,我们可以发现OnClick事件在tr标签内:
onclick="javascript:__doPostBack('GridView1$ctl02$ctl00','')"
添加一个setTimeout方法,并为其设置300毫秒延迟:
onclick="javascript:setTimeout("__doPostBack('GridView1$ctl02$ctl00','')",300)"
于是完整的RowDataBound代码如下:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.DataRow) { // Get the LinkButton control in the first cell LinkButton _singleClickButton = (LinkButton)e.Row.Cells[0].Controls[0]; // Get the javascript which is assigned to this LinkButton string _jsSingle = ClientScript.GetPostBackClientHyperlink(_singleClickButton, ""); // To prevent the first click from posting back immediately // (therefore giving the user a chance to double click) // pause the postbackfor 300 milliseconds by // wrapping the postback command in a setTimeout _jsSingle = _jsSingle.Insert(11, "setTimeout(\""); _jsSingle += "\", 300)"; // Add this javascript to the onclickAttribute of the row e.Row.Attributes["onclick"] = _jsSingle; // Get the LinkButton control in the second cell LinkButton _doubleClickButton = (LinkButton)e.Row.Cells[1].Controls[0]; // Get the javascript which is assigned to this LinkButton string _jsDouble = ClientScript.GetPostBackClientHyperlink(_doubleClickButton, ""); // Add this javascript to the ondblclick Attribute of the row e.Row.Attributes["ondblclick"] = _jsDouble; } }
这两个按钮也无需再显示,设置其Visible="false":
<Columns> <asp:ButtonFieldText="SingleClick" CommandName="SingleClick" Visible="false" /> <asp:ButtonFieldText="DoubleClick" CommandName="DoubleClick" Visible="false" /> </Columns>
现在RowCommand代码就能正确捕获和处理行单击和双击了。
注册用于验证的回发、回调数据
一切工作正常,但请记住,我们一开始在页面指令中添加了 EnableEventValidation="flase"。这并不是最安全的选项,所以我们应该将其删除。但这将导致行单击或双击时触发"回发、回调参数无效"错误。错误提示告诉我们可以通过ClientScriptManager.RegisterForEventValidation来注册用于验证的回发、回调数据。(至于EventValidation的目的已在别的文章里写得很详尽了本文不予赘述)。ClientScriptManager.RegisterForEventValidation可以通过重写 Render方法调用。这里的窍门是注册GridView中每一行的两个按钮的UniqueID。行的 UniqueID通过 GridViewRow.UniqueID获取。第一个按钮的 UniqueID可以通过在行的UniqueID后面加"$ctl00"得到,第二个按钮加"$ctl01"。
重写的 Render方法如下所示 ︰
protected override void Render(HtmlTextWriter writer) { foreach (GridViewRow r in GridView1.Rows) { if (r.RowType == DataControlRowType.DataRow) { Page.ClientScript.RegisterForEventValidation (r.UniqueID+ "$ctl00"); Page.ClientScript.RegisterForEventValidation (r.UniqueID+ "$ctl01"); } } base.Render(writer); }
至此,我们将不会再遇到"Invalid postback or callback argument" 错误。
其它控件
在源代码中,我还演示了如何在DataList和ListBox中实现此功能。代码基本相同所以我就不贴在这里了。DataList中实现行单击、双击
在DataList中,ItemTemplate的内容都被包裹在asp:Panel中,随便那两个控件分配onclick和ondblclick事件。ListBox中实现行单击、双击
在ListBox中,它本身是没有Row或Item事件的,但onclick和ondblclick 属性可以添加到控件中去。在SelectedIndexChanged事件处理程序中,通过Request.Form["__EventArgument"] 获取命令名。结论
通过查看由 ASP.NET 生成的 javascript 代码,我们可以扩展 GridView和 DataList控件的功能。为了保护你的应用程序安全,您应该尽量避免使用 EnableEventValidation="false"。一旦你理解了 EventValidation的工作原理,你可以通过 ClientScript.RegisterForEventValidation来确保您的代码按预期方式工作。源码下载地址
https://yunpan.cn/cYTKyZFjQuS2c 访问密码 036e (不嫌麻烦的话,最好前往原文地址下载)
Clickable and Double Clickable Rows with GridViewand DataListControls (ASP.NET 2.0)
Handle single and double clicks with both the GridViewand DataListControls. Also, use ClientScript.RegisterForEventValidationto register the events and avoid disabling event validation.Introduction
There are several online sources describing how to make aGridViewrow clickable anywhere on the row. There are also a few which describe how to make a row double-clickable. I haven't come across any which handle both events or deal with event validation errors in ASP.NET 2.0.
Here I will describe how to handle single and double clicks with the
GridView,
DataListand
ListBoxcontrols. I will also show how to deal with event validation without disabling it.
Background
While developing an ASP.NET application to replace an old Windows application, I was asked to keep the user experience relatively close to the original. The original application let a user select a row and perform an action on that row from a toolbar. By double clicking on a row the user could open another form with a details view of that row. This type of functionality could easily be achieved with two separate buttons on each row of aGridViewbut I needed something better than that.
Single and Double Clicking with a GridView
Create an new web application with a default page. For now, addEnableEventValidation="false"to the page directive. We will remove it later. Add a
GridViewand bind some data to it. Add two
asp:ButtonFieldcontrols using the edit columns option on the
GridView. Give these button fields command names of
SingleClickand
DoubleClick. (A select button could also be used for the
SingleClickevent but I've decided to use
asp:ButtonFieldfor both.)
<Columns> <asp:ButtonFieldText="SingleClick" CommandName="SingleClick" /> <asp:ButtonFieldText="DoubleClick" CommandName="DoubleClick" /> </Columns>
Create a
RowCommandevent for the
GridViewwith a
switchblock to capture the separate events.
For the demo, this code will write out a history of the events fired. The
SingleClickcommand will also set the
SelectedIndexof the row.
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e) { GridView_gridView = (GridView)sender; // Get the selected index and the command name int _selectedIndex = int.Parse(e.CommandArgument.ToString()); string _commandName = e.CommandName; switch(_commandName) { case ("SingleClick"): _gridView.SelectedIndex= _selectedIndex; this.Message.Text += "Single clicked GridViewrow at index " + _selectedIndex.ToString() + "<br />"; break; case ("DoubleClick"): this.Message.Text += "Double clicked GridViewrow at index " + _selectedIndex.ToString() + "<br />"; break; } }
create a
RowDataBoundevent to modify each row as it is bound. Now we need to take the client script which is used by the
SingleClickbutton for postback and assign it to the entire row.
if (e.Row.RowType == DataControlRowType.DataRow) { // Get the LinkButton control in the first cell LinkButton _singleClickButton = (LinkButton)e.Row.Cells[0].Controls[0]; // Get the javascript which is assigned to this LinkButton string _jsSingle = ClientScript.GetPostBackClientHyperlink(_singleClickButton, ""); // Add this javascript to the onclickAttribute of the row e.Row.Attributes["onclick"] = _jsSingle; }
We can also do the same for the
DoubleClickbutton, however both of these will not work together.
if (e.Row.RowType == DataControlRowType.DataRow) { // Get the LinkButton control in the second cell LinkButton _doubleClickButton = (LinkButton)e.Row.Cells[1].Controls[0]; // Get the javascript which is assigned to this LinkButton string _jsDouble = ClientScript.GetPostBackClientHyperlink(_doubleClickButton, ""); // Add this JavaScript to the ondblclick Attribute of the row e.Row.Attributes["ondblclick"] = _jsDouble; }
If we implement both these events together we will only get the functionality of the single click.
This is because when the user starts a double click, the first click is taken as a single click and the page is posted back before the second click can happen.
The JavaScript
setTimeoutmethod can be used to set a timeout on the first click, therefore giving the user a chance to complete a double click.
Looking at the source of the page, we can see the
onclickevent on the
<tr>tags:
onclick="javascript:__doPostBack('GridView1$ctl02$ctl00','')"
Add a
setTimeoutmethod and give it a timeout of 300 milliseconds:
onclick="javascript:setTimeout("__doPostBack('GridView1$ctl02$ctl00','')", 300)"
So the entire
RowDataBoundcode looks like:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
// Get the LinkButton control in the first cell
LinkButton _singleClickButton = (LinkButton)e.Row.Cells[0].Controls[0];
// Get the javascript which is assigned to this LinkButton
string _jsSingle =
ClientScript.GetPostBackClientHyperlink(_singleClickButton, "");
// To prevent the first click from posting back immediately
// (therefore giving the user a chance to double click)
// pause the postbackfor 300 milliseconds by
// wrapping the postback command in a setTimeout
_jsSingle = _jsSingle.Insert(11, "setTimeout(\"");
_jsSingle += "\", 300)";
// Add this javascript to the onclickAttribute of the row
e.Row.Attributes["onclick"] = _jsSingle;
// Get the LinkButton control in the second cell
LinkButton _doubleClickButton = (LinkButton)e.Row.Cells[1].Controls[0];
// Get the javascript which is assigned to this LinkButton
string _jsDouble =
ClientScript.GetPostBackClientHyperlink(_doubleClickButton, "");
// Add this javascript to the ondblclick Attribute of the row
e.Row.Attributes["ondblclick"] = _jsDouble;
}
}
The buttons no longer need to be visible so hide them by adding
Visible="false":
<Columns> <asp:ButtonFieldText="SingleClick" CommandName="SingleClick" Visible="false" /> <asp:ButtonFieldText="DoubleClick" CommandName="DoubleClick" Visible="false" /> </Columns>
We can now single click and double click on a row and the appropriate action will be captured in the
RowCommandcode.
Register the postback or callback data for validation
Everything is working fine, but remember that we addedEnableEventValidation="false"to the page directive. This is not the most secure option so we should remove it. This will cause an "Invalid postback or callback argument" error when a row is clicked or double clicked. The error tells us to use the
ClientScriptManager.RegisterForEventValidationmethod in order to register the postback or callback data for validation. (The purpose of
EventValidationis well documented elsewhere and beyond the scope of this article.)
The
ClientScriptManager.RegisterForEventValidationcan be called by overriding the
Rendermethod. The trick here is to register the unique id of both the buttons for each row of the
GridView. The
UniqueIDof the row is returned by
GridViewRow.UniqueID. The
UniqueIDof the first button can be generated by appending "
$ctl00" to the row's
UniqueIDand for the second button append "
$ctl01".
The overridden
Rendermethod is as follows:
protected override void Render(HtmlTextWriter writer) { foreach (GridViewRow r in GridView1.Rows) { if (r.RowType == DataControlRowType.DataRow) { Page.ClientScript.RegisterForEventValidation (r.UniqueID+ "$ctl00"); Page.ClientScript.RegisterForEventValidation (r.UniqueID+ "$ctl01"); } } base.Render(writer); }
Now we will not get any "Invalid postback or callback argument" errors.
Other Controls
In the source code, I also demonstrate how to achieve this functionality with aDataListand
ListBoxcontrols. The code is quite similar so I won't show it here.
Single and Double Clicking with a DataList
With theDataList, the contents of the
ItemTemplateare wrapped in an
asp:Panel, giving something to assign the
onclickand
ondblclickevents to.
Single and Double Clicking with a ListBox
With theListBox, there are no Row or Item events but the
onclickand
ondblclickattributes can be added to the control.
In the
SelectedIndexChangedevent handler,
Request.Form["__EventArgument"]will return the command name.
Conclusion
By looking closely at the JavaScript which is written out by ASP.NET we can extend the functionality of theGridViewand
DataListcontrols. To keep your applications secure, you should not use
EnableEventValidation="false"if at all possible. Once you understand how
EventValidationworks, you can use
ClientScript.RegisterForEventValidationto ensure your code works as intended.
History
v1.0 - 23rd Sep 2006v1.1 - 25th Sep 2006
v1.2 - 12th Nov 2006
Addition of a
ListBoxcontrol to the demo
v1.3 - 20th Dec 2006
VB.NET version of demo added to download
License
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)来源: http://www.codeproject.com/Articles/15677/Clickable-and-Double-Clickable-Rows-with-GridView
来自为知笔记(Wiz)
相关文章推荐
- java web :Context initialization failed
- kali安装搜狗输入法
- 使用XStream进行XML与对象的互相转换 下划线问题
- 程序猿,你累吗?
- HDU 1394 (树状数组 & 线段树 两种做法)
- leetcode 解题 String to Integer (atoi)(C&python)
- PSP记录个人项目耗时情况
- FNV哈希算法
- jumpserver 安装
- OC中字符串类和数值类
- AfxGetMainWnd() return NULL
- eclipse中如何查看sdk
- ThinkPHP框架下基于RBAC的权限控制模式详解
- POJ 2752 Seek the Name, Seek the Fame
- return
- HDU 3074 带权并查集
- 中国剩余定理
- LINUX常见命令学习
- centos6.5内核升级
- Java开发之String与StringBuffer