GridView 和 DataList 控件的可点击和双击行(ASP.NET 2.0)






4.56/5 (40投票s)
处理 GridView 和 DataList 控件的单击和双击事件。此外,使用 ClientScript.RegisterForEventValidation 注册事件并避免禁用事件验证。
引言
网上有许多资料介绍了如何使 GridView 的行在任何位置都可点击。也有一些资料介绍了如何使行可双击。但我还没有找到任何能同时处理这两种事件或处理 ASP.NET 2.0 中事件验证错误的资料。
在这里,我将介绍如何处理 GridView、DataList 和 ListBox 控件的单击和双击事件。我还将展示如何在不禁用事件验证的情况下处理它。
背景
在开发一个 ASP.NET 应用程序来替换一个旧的 Windows 应用程序时,我被要求尽可能地保留用户体验。原始应用程序允许用户选择一行并在工具栏上对该行执行操作。通过双击一行,用户可以打开另一个包含该行详细信息的表单。这种功能可以通过 GridView 的每一行上的两个单独的按钮轻松实现,但我需要比这更好的东西。
GridView 的单击和双击
创建一个新的 Web 应用程序,包含一个默认页面。暂时,将 EnableEventValidation="false"
添加到页面指令中。稍后我们将删除它。添加一个 GridView 并为其绑定一些数据。使用 GridView 上的“编辑列”选项添加两个 asp:ButtonField
控件。为这些按钮字段设置命令名称为 SingleClick
和 DoubleClick
。(选择按钮也可以用于 SingleClick
事件,但我决定对两者都使用 asp:ButtonField
。)
<Columns>
<asp:ButtonField Text="SingleClick" CommandName="SingleClick" />
<asp:ButtonField Text="DoubleClick" CommandName="DoubleClick" />
</Columns>
为 GridView 创建一个 RowCommand
事件,并使用一个 switch
块来捕获单独的事件。
在此演示中,此代码将记录触发事件的历史记录。SingleClick
命令还将设置行的 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 GridView row at index "
+ _selectedIndex.ToString() + "<br />";
break;
case ("DoubleClick"):
this.Message.Text += "Double clicked GridView row 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 onclick Attribute of the row
e.Row.Attributes["onclick"] = _jsSingle;
}
我们也可以对 DoubleClick
按钮做同样的事情,但是这两者不能同时工作。
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
方法可以用来为第一次单击设置一个超时,从而给用户完成双击的机会。
查看页面源代码,我们可以看到 <tr>
标签上的 onclick
事件
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 onclick Attribute 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:ButtonField Text="SingleClick" CommandName="SingleClick"
Visible="false" />
<asp:ButtonField Text="DoubleClick" CommandName="DoubleClick"
Visible="false" />
</Columns>
现在我们可以单击和双击一行,并在 RowCommand
代码中捕获相应的操作。
注册用于验证的回发或回调数据
一切正常,但请记住,我们在页面指令中添加了 EnableEventValidation="false"
。这不是最安全的选择,所以我们应该删除它。这会导致在单击或双击行时出现“无效的回发或回调参数”错误。错误提示我们使用 ClientScriptManager.RegisterForEventValidation
方法来注册用于验证的回发或回调数据。(EventValidation
的作用已在其他地方有详细说明,超出本文范围。)
可以通过重写 Render
方法来调用 ClientScriptManager.RegisterForEventValidation
。诀窍在于为 GridView
的每一行的两个按钮注册唯一的 ID。行的 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);
}
现在我们不会再遇到“无效的回发或回调参数”错误了。
其他控件
在源代码中,我还演示了如何使用 DataList
和 ListBox
控件实现此功能。代码非常相似,因此我在此不展示。
DataList 的单击和双击
对于 DataList
,ItemTemplate
的内容被包裹在一个 asp:Panel
中,提供了一个可以为其分配 onclick
和 ondblclick
事件的对象。
ListBox 的单击和双击
对于 ListBox
,没有行或项事件,但可以将 onclick
和 ondblclick
属性添加到控件中。
在 SelectedIndexChanged
事件处理程序中,Request.Form["__EventArgument"]
将返回命令名称。
结论
通过仔细查看 ASP.NET 生成的 JavaScript,我们可以扩展 GridView
和 DataList
控件的功能。为了保持应用程序安全,如果可能,应避免使用 EnableEventValidation="false"
。一旦您理解了 EventValidation
的工作原理,就可以使用 ClientScript.RegisterForEventValidation
来确保您的代码按预期工作。
历史
- v1.0 - 2006 年 9 月 23 日
- v1.1 - 2006 年 9 月 25 日
- v1.2 - 2006 年 11 月 12 日
在演示中添加了 ListBox 控件 - v1.3 - 2006 年 12 月 20 日
添加了 VB.NET 演示版本到下载文件中