Well I have a strange problem.
I have a page with 2 DropDownLists on it and a custom web-user-control. The custom web user control has an UpdatePanel within it, and an Ajax Timer control within the UpdatePanel to periodically update a listing of stuff.
When I "drop-down" one of the DropDownLists and hover over (not click on) an option while the Timer control within the UpdatePanel asynchronously posts back to the server, the DropDownList "autopostbacks" to the server!
I'm trying to figure out why an asynchronous postback would cause the DropDownList to act as if I selected/clicked on an option so that I can find a way around this issue.
Now it's really simple to reproduce this problem. Create a Web User control called "TimerUpdatedListing"...this is the ASPX code markup for the web user control:
<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="TimerUpdatedListing.ascx.vb" Inherits="MyNamespace.TimerUpdatedListing" %>
<div style="width: 150px; height: 150px; overflow: auto; border: solid 1px navy;">
<asp:UpdatePanel ID="anUpdatePanel" runat="server">
<ContentTemplate>
<asp:Repeater ID="aRepeater" runat="server">
<ItemTemplate>
<div style="border-bottom: solid 1px #EEC900; margin: 3px; padding: 2px;">
Id:
<%#Eval("Id")%>
<br />
Time:
<%#Eval("Time")%>
</div>
</ItemTemplate>
</asp:Repeater>
<asp:Timer ID="aTimer" runat="server" Interval="2000">
</asp:Timer>
</ContentTemplate>
</asp:UpdatePanel>
</div>
This is the VB.NET server side code for the web user control:
Public Partial Class TimerUpdatedListing
Inherits System.Web.UI.UserControl
Private _aListOFThings As List(Of Things)
Private Sub aTimer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles aTimer.Tick
If Session("_aListOfThings") Is Nothing Then
_aListOFThings = New List(Of Things)
Else
_aListOFThings = CType(Session("_aListOfThings"), List(Of Things))
End If
If _aListOFThings.Count > 9 Then
_aListOFThings = New List(Of Things)
End If
_aListOFThings.Add(New Things((_aListOFThings.Count + 1).ToString, Now.ToString("hh:mm:ss")))
Session("_aListOfThings") = _aListOFThings
aRepeater.DataSource = _aListOFThings
aRe开发者_运维技巧peater.DataBind()
End Sub
Private Class Things
Private _time As String
Private _id As String
Public Property Time() As String
Get
Return _time
End Get
Set(ByVal value As String)
_time = value
End Set
End Property
Public Property ID() As String
Get
Return _id
End Get
Set(ByVal value As String)
_id = value
End Set
End Property
Public Sub New(ByVal id As String, ByVal time As String)
_id = id
_time = time
End Sub
End Class
End Class
Now, in an ASPX page called WebForm1.aspx, add 2 DropDownLists and the web user control:
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="WebForm1.aspx.vb" Inherits="MyNamespace.WebForm1" %>
<%@ Register Src="TimerUpdatedListing.ascx" TagName="TimerUpdatedListing" TagPrefix="uc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Test</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="true">
<asp:ListItem Text="1" Value="1" />
<asp:ListItem Text="2" Value="2" />
<asp:ListItem Text="3" Value="3" />
<asp:ListItem Text="4" Value="4" />
<asp:ListItem Text="5" Value="5" />
</asp:DropDownList>
<asp:Label ID="selectedValue1" runat="server"></asp:Label>
<br />
<asp:DropDownList ID="DropDownList2" runat="server" AutoPostBack="true">
<asp:ListItem Text="a" Value="a" />
<asp:ListItem Text="b" Value="b" />
<asp:ListItem Text="c" Value="c" />
<asp:ListItem Text="d" Value="d" />
<asp:ListItem Text="e" Value="e" />
</asp:DropDownList>
<asp:Label ID="selectedValue2" runat="server"></asp:Label>
<br />
<br />
<uc1:TimerUpdatedListing ID="TimerUpdatedListing1" runat="server" />
</div>
</form>
</body>
</html>
Here is the VB.NET server side code for the WebForm1.aspx page:
Public Partial Class WebForm1
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If String.IsNullOrEmpty(Request.Params("ddl1")) = False Then
selectedValue1.Text = Request.Params("ddl1")
End If
If String.IsNullOrEmpty(Request.Params("ddl2")) = False Then
selectedValue2.Text = Request.Params("ddl2")
End If
End Sub
Private Sub DropDownList1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList1.SelectedIndexChanged
Response.Redirect(Request.Url.LocalPath + "?ddl1=" + DropDownList1.SelectedValue.ToString, True)
End Sub
Private Sub DropDownList2_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList2.SelectedIndexChanged
Response.Redirect(Request.Url.LocalPath + "?ddl2=" + DropDownList2.SelectedValue.ToString, True)
End Sub
End Class
Thanks,
-Frinny
Here is an example of using triggers to trigger your update panel. Put the timer.tick event as a trigger and see what happens
http://www.asp.net/ajax/tutorials/understanding-asp-net-ajax-updatepanel-triggers
PS: I don't think the timer has to be included within the update panel. I actually build my timers in the codebehind and keep them out of the markup all together.
I attempted two different solutions to this problem.
The first thing I did was to check the Request.Params("__EVENTTARGET") to see if it matched the DropDownList. If it matched then I would call the Response.Redirect() method.
For example:
Public Partial Class WebForm1
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If String.IsNullOrEmpty(Request.Params("ddl1")) = False Then
selectedValue1.Text = Request.Params("ddl1")
End If
If String.IsNullOrEmpty(Request.Params("ddl2")) = False Then
selectedValue2.Text = Request.Params("ddl2")
End If
End Sub
Private Sub DropDownList1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList1.SelectedIndexChanged
Dim ctrlNameThatCausedPostback As String = Request.Params("__EVENTTARGET")
If String.IsNullOrEmpty(ctrlNameThatCausedPostback) = False AndAlso Page.FindControl(ctrlNameThatCausedPostback) Is DropDownList1 Then
Response.Redirect(Request.Url.LocalPath + "?ddl1=" + DropDownList1.SelectedValue.ToString, True)
End If
End Sub
Private Sub DropDownList2_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList2.SelectedIndexChanged
Dim ctrlNameThatCausedPostback As String = Request.Params("__EVENTTARGET")
If String.IsNullOrEmpty(ctrlNameThatCausedPostback) = False AndAlso Page.FindControl(ctrlNameThatCausedPostback) Is DropDownList2 Then
Response.Redirect(Request.Url.LocalPath + "?ddl2=" + DropDownList2.SelectedValue.ToString, True)
End If
End Sub
End Class
I noticed that this didn't always work. There were times when I selected an option in the DropDownList and the Redirect wouldn't take place because the timer tick and the selected index changed event happened at the same time.
So the second approach I took was to check to see if the page is in an asynchronous postback to the server. If it was, then I knew that it was the timer tick event taking place and that the Redirect shouldn't occur.
For example:
Public Partial Class WebForm1
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If String.IsNullOrEmpty(Request.Params("ddl1")) = False Then
selectedValue1.Text = Request.Params("ddl1")
End If
If String.IsNullOrEmpty(Request.Params("ddl2")) = False Then
selectedValue2.Text = Request.Params("ddl2")
End If
End Sub
Private Sub DropDownList1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList1.SelectedIndexChanged
If ScriptManager.GetCurrent(Me.Page).IsInAsyncPostBack = False Then
Response.Redirect(Request.Url.LocalPath + "?ddl1=" + DropDownList1.SelectedValue.ToString, True)
End If
End Sub
Private Sub DropDownList2_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList2.SelectedIndexChanged
If ScriptManager.GetCurrent(Me.Page).IsInAsyncPostBack = False Then
Response.Redirect(Request.Url.LocalPath + "?ddl2=" + DropDownList2.SelectedValue.ToString, True)
End If
End Sub
End Class
This helped, and the likelihood that the Redirect would occur properly was better than the previous approach; however, it still isn't 100%.
-Frinny
精彩评论