Firefox在我的asp.net应用程序中导致双重PostBack。 IE和Safari不会导致问题。
我有一个表单供用户填写,它位于MultiView中显示的第二个View中。 MultiView位于UpdatePanel内,因此视图通过部分页面回发更新。一旦他们被呈现,他们点击提交的表格,他们的条目存储在数据库中。
为了防止用户双击提交按钮,我在提交表单后使用Javascript来禁用按钮。网上有几种技术可以展示如何做到这一点,而且我已经使用了这个特定的解决方案已有一段时间了。正如我所提到的,只有Firefox会导致双重PostBack。这似乎是一个常见的问题,如果你谷歌为它,你会发现一些讨论,但我还没有找到答案。大多数讨论都围绕着一个空的src属性。我使用的是ImageButton,但在我的情况下,src属性永远不应为空。
让我们看看代码。
首先是标记(缩写):
<asp:UpdatePanel ID="UP1" runat="server">
<ContentTemplate>
<asp:MultiView id="MV1" runat="server" ActiveViewIndex="0">
<asp:View id="View1" runat="server">
Some markup and some asp.net controls
</asp:View>
<asp:View id="View2" runat="server">
<asp:TextBox ID="NameTB" runat="server" />
<asp:RequiredFieldValidator ID="NameTBRFV" runat="server"
ControlToValidate="NameTB" ErrorMessage="Required"
CssClass="validate" />
<asp:ImageButton ID="Submit" runat="server"
ImageUrl="Images/AlumniSubmitButton.jpg" OnClick="Submit_Click" />
</asp:View>
</asp:MultiView>
<ContentTemplate>
</asp:UpdatePanel>
第二个页面加载背后的代码:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Utilities.BindSafeClick(Submit, "Images/AlumniSubmitButton.jpg");
}
}
第三个添加禁用按钮的onclick的代码:
public static void BindSafeClick(Control control, String waitMessage)
{
StringBuilder sbValid = new StringBuilder();
Page myPage = control.Page;
if (control is Button)
{
Button myControl = (Button)control;
sbValid.Append("if (typeof(Page_ClientValidate) == 'function') { ");
sbValid.Append("if (Page_ClientValidate() == false) { return false; }} ");
sbValid.Append("this.value = '" + waitMessage + "';");
sbValid.Append("this.disabled = true;");
sbValid.Append(myPage.ClientScript.GetPostBackEventReference(myControl, null));
sbValid.Append(";");
// the following depends on if submit control has UseSubmitBehavior set.
// Basically set the opposite here.
if (myControl.UseSubmitBehavior)
{
sbValid.Append("return false;");
}
else
{
sbValid.Append("return true;");
}
myControl.Attributes.Add("onclick", sbValid.ToString());
}
else if (control is LinkButton)
{
LinkButton myControl = (LinkButton)control;
sbValid.Append("if (typeof(Page_ClientValidate) == 'function') { ");
sbValid.Append("if (Page_ClientValidate() == false) { return false; }} ");
sbValid.Append("this.innerText = '" + waitMessage + "';");
sbValid.Append("this.disabled = \"disabled\";");
sbValid.Append(myPage.ClientScript.GetPostBackEventReference(myControl, null));
sbValid.Append(";");
myControl.Attributes.Add("onclick", sbValid.ToString());
}
else if (control is ImageButton)
{
ImageButton myControl = (ImageButton)control;
sbValid.Append("if (typeof(Page_ClientValidate) == 'function') { ");
sbValid.Append("if (Page_ClientValidate() == false) { return false; }} ");
sbValid.Append("this.src = '" + waitMessage + "';");
sbValid.Append("this.disabled = true;");
sbValid.Append(myPage.ClientScript.GetPostBackEventReference(myControl, null));
sbValid.Append(";");
myControl.Attributes.Add("onclick", sbValid.ToString());
}
}
当浏览器收到表单时我查看了渲染的输出,并注意到onclick javascript似乎做了两个回发。
在Safari和IE中呈现相同的代码。
为什么Firefox会是唯一一个做两个PostBacks的人?
这是渲染的输出(添加的换行符和onclick的间距以便于阅读)
<input type="image" name="Submit" id="Submit" src="Images/AlumniSubmitButton.jpg"
onclick="
if (typeof(Page_ClientValidate) == 'function')
{
if (Page_ClientValidate() == false)
{
return false;
}
}
this.src = 'Images/AlumniSubmitButton.jpg';
this.disabled = true;
__doPostBack('Submit','');
WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("Submit", "", true, "", "", false, false))" style="border-width:0px;" />
答案 0 :(得分:3)
这很简单,因为图像路径错误。当FireFox
无法找到图片时,它会再次进行回发。我花了一段时间才弄明白。
答案 1 :(得分:2)
Firefox在JavaScript语句的末尾需要return false;
。在JavaScript语句末尾添加return false;
也将被其他浏览器正确解释。
所以不要写这个;
yourButtonControl.Attributes.Add("onclick", "if (Page_ClientValidate('nameOfValidationGroup') == false) { return false; } " + ``Page.ClientScript.GetPostBackEventReference(yourButtonControl, String.Empty) + ";this.disabled = true;");
...写这个;
yourButtonControl.Attributes.Add("onclick", "if (Page_ClientValidate('nameOfValidationGroup') == false) { return false; } " + Page.ClientScript.GetPostBackEventReference(yourButtonControl, String.Empty) + ";this.disabled = true; return false;");
我花了几天的试验和错误,以及大量的测试来确定为什么我的数据层逻辑突然开始抛出以下错误:
Transaction (Process ID "...") was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
......只是发现Firefox是罪魁祸首。
在一天结束时,这些错误可以提高你的知识和技能。 ; - ]
我希望这可以帮助很多其他开发人员。
JavaScript并不邪恶。它不像托管代码那么友好。
帕特里克
答案 2 :(得分:1)
尝试向该按钮添加回发触发器。关闭UpdatePanel标记上方的触发器部分。
示例代码:
<asp:UpdatePanel ID="UP1" runat="server">
<ContentTemplate>
<asp:MultiView id="MV1" runat="server" ActiveViewIndex="0">
<asp:View id="View1" runat="server">
Some markup and some asp.net controls
</asp:View>
<asp:View id="View2" runat="server">
<asp:TextBox ID="NameTB" runat="server" />
<asp:RequiredFieldValidator ID="NameTBRFV" runat="server"
ControlToValidate="NameTB" ErrorMessage="Required"
CssClass="validate" />
<asp:ImageButton ID="Submit" runat="server"
ImageUrl="Images/AlumniSubmitButton.jpg" OnClick="Submit_Click" />
</asp:View>
</asp:MultiView>
</ContentTemplate>
<Triggers>
<asp:PostBackTrigger ControlID="Submit" />
</Triggers>
</asp:UpdatePanel>
答案 3 :(得分:1)
前一段时间我遇到了与ImageButton相同的问题,当我将ImageButton AlternateText属性设置为非空字符串时,问题就消失了。
答案 4 :(得分:1)
一种解决方法是将按钮放在DataGridView中。这样可以防止使用FireFox进行双重回发。
创建DataGridView:
<asp:GridView ID="GridViewButton" ShowHeader="false" runat="server" AutoGenerateColumns="false"
GridLines="None" OnRowCommand="GridViewButton_RowCommand" CellPadding="0" OnDataBound="GridViewButton_DataBound">
<Columns>
<asp:ButtonField Text="Save" CommandName="Save" ButtonType="Button">
</asp:ButtonField>
</Columns>
</asp:GridView>
在PageLoad上,使用虚拟数据填充DataGridView,以便显示按钮:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Dim dt As New DataTable
dt.Columns.Add(New DataColumn("col1"))
Dim dr As DataRow = dt.NewRow
dt.Rows.Add(dr)
Me.GridViewButton.DataSource = dt
Me.GridViewButton.DataBind()
End Sub
在DataBound上,设置javascript以禁用按钮onclick:
Protected Sub GridViewButton_DataBound(ByVal sender As Object, ByVal e As System.EventArgs)
CType(Me.GridViewButton.Rows(0).Cells(0).Controls.Item(0), Button).Attributes.Add("onclick", "this.disabled=true;")
End Sub
处理点击事件:
Protected Sub GridViewButton_RowCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs)
If e.CommandName = "Save" Then
//Do something here
End If
End Sub
答案 5 :(得分:0)
似乎_doPostBack()和WebForm_DoPostBackWithOptions()都在回发。两者相互冲突。有关详情,请参阅this
非常有趣..