[本文系原创翻译,转载请注明出处]
Note:
英文原文链接:http://www.codeproject.com/KB/webforms/DoubleClickGridviewRow.aspx
网上有很多方法不仅可以实现在GridView的一行的任意位置单击实现选中功能,而且也可以实现双击选中的功能。但我还没有遇到过能同时具有单击和双击功能,并且可以很好的解决event validation errors 。
这里,我将给出一种可以在ASP.NET2.0下同时实现行的单/双击选中行的方法,其适用范围有 GridView
, DataList ,
ListBox等控件。
背景:
当开发一个ASP.NET的应用程序去代替传统的Windows应用程序,经常被要去使其用户体验接近于传统模式。传统的应用程序允许用户选中工具栏中的行,并执行其事件响应。通过点击一行,可以打开另一个Form,并看到其细节。这种功能可以很容易的通过在GridView中设置两个隐藏的ButtonField去实现,当然我要做的比这样更好。
可单/双击的GridView
创建一个Web应用程序,其默认页面为Default.aspx. 现在, 事
EnableEventValidation="false"
. 我们以后再移除它.添加一个 GridView并绑定数据源
. 在GridVIew上点击-编辑列-添加两个 asp:ButtonField
. 分别为其命名为 SingleClick和
DoubleClick
.
<Columns>
<asp:ButtonField Text="SingleClick" CommandName="SingleClick" />
<asp:ButtonField Text="DoubleClick" CommandName="DoubleClick" />
</Columns>
添加GridView的
RowCommand事件,并用Switch语句去捕获其选中事件。下面的示例将在页面显示你所选中过GridView行的索引列表。
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 事件在绑定数据时修改每一行的属性。现在,我们需要为每一行添加客户端脚本(即添加onclick),该脚本作用于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;
}
虽然我们实现了响应单击和双击事件,但实际我们只能得到单击响应的功能。因为如果用户进行了双击,双击中的第一次就被作为单击响应。JS中的setTimeout方法可以对第一次响应设置超时,这样用户就可以完成一次双击。
οnclick="javascript:__doPostBack('GridView1$ctl02$ctl00','')"
将超时设置为300毫秒
οnclick="javascript:setTimeout
("__doPostBack('GridView1$ctl02$ctl00','')", 300)"
完整的DataRowBound的代码如下:
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;
}
}
此时,这两个按钮应该设置为隐藏
<Columns>
<asp:ButtonField Text="SingleClick" CommandName="SingleClick"
Visible="false" />
<asp:ButtonField Text="DoubleClick" CommandName="DoubleClick"
Visible="false" />
</Columns>
现在,RowCommand可以同时捕捉到GridView一行的单双击事件了。
注册用以验证的postback 和callback数据
一切都运行的很好,请别忘记一开始我们设置了 EnableEventValidation="false" ,这不是安全的选项,我们要移除它。这在单击时将导致出现"Invalid postback or callback argument" 错误。这个错误告诉我们去使用theClientScriptManager.RegisterForEventValidation 去注册postback或callback数据。
ClientScriptManager.RegisterForEventValidation可以被重载的Render方法调用。这里的关键是注册GridView一行的两个按钮个unique Id。每一行的UniqueID被转换为GridView.UniqueID,第一个按钮的UniqueID仅需要在GridView.UniqueId的后面就附加上”$ctl00“,第二个按钮则附加上 "$ctl01".
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”错误了。
结论
通过JS与ASP.NET的紧密结合,我们可以扩展GridView和DataList的功能。为了你的程序的安全,如果可以的话,你不应该将EnableEventValidation="false"
。一旦你理解了EventValidation是如何工作的,你可以使用ClientScript.RegisterForEventValidation却包你的代码执行的更安全