如何在gridview的rowcommand事件中在新选项卡中打开页面?
Posted
技术标签:
【中文标题】如何在gridview的rowcommand事件中在新选项卡中打开页面?【英文标题】:How to open a page in a new tab in the rowcommand event of gridview? 【发布时间】:2013-01-25 17:39:14 【问题描述】:我有以下代码:
protected void gv_inbox_RowCommand(object sender, GridViewCommandEventArgs e)
int index = Convert.ToInt32(e.CommandArgument);
if (e.CommandName == "sign")
Session["TransYear"] = int.Parse(((HiddenField)gv_inbox.Rows[index].Cells[1].FindControl("HDN_TransYear")).Value);
Session["MailNumber"] = int.Parse(((HiddenField)gv_inbox.Rows[index].Cells[1].FindControl("HDN_MailNumber")).Value);
Response.Redirect("Signature.aspx", false);
//Response.Write("<script>");
//Response.Write("window.open('Signature.aspx','_blank')");
//Response.Write("</script>");
我想在新标签页或窗口中打开页面。注释代码会这样做,但是当refresh
原始页面导致错误时。如何在我的gridview 的行命令事件中以正确的方式在新窗口或选项卡中打开Signature.aspx
。
【问题讨论】:
如果您想在新标签页中打开某些内容,那么Response.Redirect()
可能不是最佳选择。这将重定向当前浏览器选项卡中的当前响应。在新选项卡中打开内容的最简单方法是完全避免使用服务器端代码,只需制作一个带有 target
或 _blank
的链接。或者如果它需要是一个按钮,javascript 也可以在新选项卡中打开一些东西。看起来您正在尝试在引导用户之前设置一些值,但我想链接可以只包含查询字符串中的这些值,Signature.aspx
页面可以从那里使用它们。
@David 有正确的路要走。特别是因为会话变量在部署到网络场时会增加复杂性。
确实,我什至没有想到这一点。 (我已经有一段时间没有对我的 Web 应用程序痴迷于 RESTful 了,所以我有一段时间不必过多考虑 Web 农场了。)作为一般规则,请求本身应该携带所需的输入资源来生成响应。
hmmm,但我想在打开新窗口之前设置会话!
【参考方案1】:
您要做的是使用ScriptManager
进行 JavaScript 调用。
您定义的 JavaScript sn-p 有效,但是,您需要 ScriptManager
来为您执行它。
String js = "window.open('Signature.aspx', '_blank');";
ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "Open Signature.aspx", js, true);
使用Response.Write
的问题是在PostBack
期间,浏览器将不执行脚本标签。另一方面,当使用ScriptManager.RegisterClientScriptBlock
时,ASP.NET ScriptManager
会自动执行代码。
更新 - 2013/02/14
按照Vladislav's answer 中的建议,使用ClientScript
与ScriptManager
;区别在于ClientScript
仅用于同步 回发(没有asp:UpdatePanel
),ScriptManager
用于异步回发(使用asp:UpdatePanel
)。
此外,根据以下作者的评论 - 将 asp:GridView
包含在 asp:UpdatePanel
中将消除确认刷新的浏览器消息。同步回发后刷新页面时(没有asp:UpdatePanel
),浏览器会重新发送最后一条命令,导致服务器再次执行相同的进程。
最后,当将asp:UpdatePanel
与ScriptManager.RegisterClientScriptBlock
结合使用时,请确保将第一个和第二个参数更新为asp:UpdatePanel
对象。
ScriptManager.RegisterClientScriptBlock(updatePanel1, updatePanel1.GetType(), "Open Signature.aspx", js, true);
【讨论】:
当我刷新主页后,我收到以下消息:To display this page, Firefox must send information that will repeat any action (such as a search or order confirmation) that was performed earlier.
我不想显示此消息.. 代码 :: String js = "window.open('Signature.aspx', '_blank');"; ClientScript.RegisterClientScriptBlock(this.GetType(), "Open Signature.aspx", js, true);
@just_name 您收到该消息是因为您手动刷新页面 - 它与 JavaScript 或 ClientScript/ScriptManager 无关。 Firefox 只是警告您,如果您手动刷新页面,之前的所有数据都将再次发送。为避免此消息,请将 GridView 括在 asp:UpdatePanel
中。
我将gridview
附在更新面板中,但仍然收到相同的消息!!
你能用更多的标记代码更新你的问题吗?同步回发会发生一些事情,将用户带到您的当前页面;或者您是通过 <form action="this_page">
或 POST/PUT/DELETE 命令到达此页面的。【参考方案2】:
首先,这里的练习是如何将简单的值从一个页面传递到另一个页面。
在您的情况下,这些只是键/值,因此您可以通过 GET 传递它们。
您需要在每一行都呈现它,而不是命令按钮。
<a href="Signature.aspx?TransYear=value1&MailNumber=value2" target="_blank">
Sign
</a>
在本例中,value1 和 value2 是您分别写入 HDN_TransYear 和 HDN_MailNumber 的值。
如果您想使用会话变量,您必须在 Signature.aspx 中执行以下操作:
Session["TransYear"]
Session["MailNumber"]
现在应该改成这样:
Request.QueryString["TransYear"]
Request.QueryString["MailNumber"]
这通常会满足您的要求。但是……
如果你说这种方法不安全,那么任何人都可以通过更改参数值来玩弄查询字符串变量,那么……
为每一行计算一个签名,将此签名作为第三个参数放在查询字符串中,并验证另一侧的值和签名。
如何计算签名,这取决于你。这就是你的秘诀。有很多散列函数和加盐算法。
举个很简单的例子:
string signature = CRC32(HDN_TransYear + "stuff that you only know" + HDN_MailNumber)
那么你的链接应该是这样的:
<a href="Signature.aspx?TransYear=2012&MailNumber=1&sig=8d708768" target="_blank">
Sign
</a>
在 Signature.aspx 中,您使用来自查询字符串的值和“您只知道的东西”来再次计算 CRC32 签名,并根据在查询字符串中作为参数传递的签名进行验证。
没有剧情。
【讨论】:
完美 我同意这种方法。 @just_name 这是另一件事要解决。即使您使用“原始”方法(回发到服务器、写入会话、注入 javascript 并打开一个新选项卡),您最终也会遇到同样的问题。假设您在 Signature.aspx 中将更改保存到您的 gridview 正在使用的同一数据源(通常是数据库),那么最好的方法是手动刷新网格(在页面的某处使用刷新按钮)。如果您需要另一种方式,服务器告诉客户端“请立即刷新”,该技术称为“彗星”,值得一试,但并不那么简单。【参考方案3】:我宁愿使用
ClientScript.RegisterStartupScript(this.GetType(), "Open Signature.aspx", js, true);
你不需要刷新你的页面。
页面从回发中恢复后,脚本块将触发。
只是一个建议: - 在您的情况下是否可以使用 DataKeys 来检索 TransYear 和 MailNumber 的值而不是使用 HiddenFields
【讨论】:
【参考方案4】:我们已经成功使用以下代码几年了。这几种方法是从一个更大的通用模块中提取出来的,但我想我已经包含了所有内容......
public class Utilities
/// <summary>
/// This will return the first parent of the control that is an update panel
/// </summary>
/// <param name="source">The source control</param>
/// <returns>The first parent found for the control. Null otherwise</returns>
public static UpdatePanel GetFirstParentUpdatePanel(Control source)
Page currentPage = source.Page;
UpdatePanel updatePanel = null;
Type updatePanelType = typeof(UpdatePanel);
object test = source.Parent;
while (test != null && test != currentPage)
// is this an update panel
if (test.GetType().FullName == updatePanelType.FullName)
// we've found the containing UpdatePanel
updatePanel = (UpdatePanel)test;
// check the next parent
test = ((Control)test).Parent;
// next test
return updatePanel;
/// <summary>
/// This will open the specified url in a new window by injecting a small script in
/// the current page that is run when the page is sent to the client's browser.
/// This method accounts for the presence of update panels and script managers on the
/// page that the control resides in.
/// </summary>
/// <param name="source">The control that the call is being made from</param>
/// <param name="url">The URL to bring up in a new window</param>
public static void RedirectToNewWindow(Control source, string url)
// create the script to register
string scriptKey = "_NewWindow";
string script = "window.open('" + url + "');";
RegisterControlScript(source, scriptKey, script);
/// <summary>
/// This will register a script for a specific control accounting for the control's UpdatePanel
/// and whether or not there is a script manager on the page
/// </summary>
/// <param name="source">The control that will be affected by the script</param>
/// <param name="scriptKey">A unique key for the script</param>
/// <param name="script">The script that will affect the control</param>
public static void RegisterControlScript(Control source, string scriptKey, string script)
// get the control's page
Page currentPage = source.Page;
// does the control reside in an UpdatePanel
UpdatePanel updatePanel = GetFirstParentUpdatePanel(source);
// did we find the UpdatePanel
if (updatePanel == null)
// register the script on the page (works outside the control being in an update panel)
currentPage.ClientScript.RegisterStartupScript(currentPage.GetType(), scriptKey,
script, true /*addScriptTags*/);
else
// register the script with the UpdatePanel and ScriptManger
ScriptManager.RegisterClientScriptBlock(source, source.GetType(), scriptKey,
script, true /*addScriptTags*/);
// did we find the UpdatePanel
然后,为了你的使用,你会打电话
protected void gv_inbox_RowCommand(object sender, GridViewCommandEventArgs e)
int index = Convert.ToInt32(e.CommandArgument);
if (e.CommandName == "sign")
Session["TransYear"] = int.Parse(((HiddenField)gv_inbox.Rows[index].Cells[1].FindControl("HDN_TransYear")).Value);
Session["MailNumber"] = int.Parse(((HiddenField)gv_inbox.Rows[index].Cells[1].FindControl("HDN_MailNumber")).Value);
Utilities.RedirectToNewWindow(gv_inbox, "Signature.aspx");
不是最简洁的代码,因为我提取了这些辅助方法,但你明白了。上面的代码将在 c#2.0 及更高版本上运行,并且无论 UpdatePanel
嵌套如何,或者即使根本没有使用 UpdatePanel
s 也可以运行
【讨论】:
【参考方案5】:为什么要在打开新窗口之前设置会话?
如果在打开新窗口后设置会话是可以的,我认为你可以在Signature.aspx
后面的代码中进行设置,考虑到你将所需的参数作为@David 的查询字符串传递指出。
【讨论】:
【参考方案6】:为什么我们要使用回发来在不同的 URL 窗口中打开链接。
在创建控件链接时,我们可以将 signature.aspx 所需的值作为 Querystring 嵌入到链接控件中,这将只是一个简单的浏览器点击。
我希望这是简单而干净的。
【讨论】:
以上是关于如何在gridview的rowcommand事件中在新选项卡中打开页面?的主要内容,如果未能解决你的问题,请参考以下文章
在 GridView RowCommand 中获取 DataKey 值