Dave Dave - 4 months ago 40
ASP.NET (C#) Question

__doPostBack only works if there is a LinkButton, Calendar or WizardStep control on the page

I have identified a problem with __doPostBack and found a work around. I am seeking an explanation for the cause and/or a better solution than my work around.

Scenario:
I have a dropdown populated with the values; "-Select-", "One" & "Two". If the user selects "One" than client side script is executed. If the user selects "Two" than server side script is executed.

Problem:
The client script initiates the postback by calling __doPostBack. However, no post back actually occurs unless there is also a LinkButton, Calendar or WizardStep control on the page. I actually went through all of the standard tools in the Visual Studio Toolbox and tested them all. It has to be one of those three.

Work Around:
Add a link button surrounded by a span with display set to none.

<span style="display:none;">
<asp:LinkButton ID="LinkButton1" runat="server">LinkButton</asp:LinkButton>
</span>


Question: Can somebody provide an explanation for this behavior or provide a better fix than my "Work Around"?

Source - Javascript (I placed it between the head tags)

<script language="javascript" type="text/javascript">
function DropDownList1_change(elementRef) {
var selectedIndex = elementRef.selectedIndex;
if (selectedIndex > 0) {
var selectedValue = elementRef.options[selectedIndex].value;
if (selectedValue == "One") {
alert("Because you selected 'One', special javascript code will be executed");
// Special javascript code goes here
return;
}
else if (selectedValue == "Two") {
// Special server code gets executed on server DropDownList1_SelectedIndexChanged
__doPostBack('DropDownList1', '');
}
}
}
</script>


Source - ASPX Controls

<asp:DropDownList ID="DropDownList1" runat="server" onchange="DropDownList1_change(this)" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged">
<asp:ListItem>-Select-</asp:ListItem>
<asp:ListItem>One</asp:ListItem>
<asp:ListItem>Two</asp:ListItem>
</asp:DropDownList>
<br />

<!-- For some unknown reason __doPostBack only works if there is a LinkButton, Calendar or WizardStep control on the page -->
<span style="display:none;">
<asp:LinkButton ID="LinkButton1" runat="server">LinkButton</asp:LinkButton>
</span>

Time of last Post Back: <asp:Label ID="Label1" runat="server"></asp:Label><br />
Time of OnSelectedIndexChanged: <asp:Label ID="Label2" runat="server"></asp:Label>


Source - Code Behind

protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = DateTime.Now.ToLongTimeString();
}

protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
Label2.Text = DateTime.Now.ToLongTimeString();
}


Additional Resource - I found the following article after posting this question. Its a very old Microsoft article and the only Microsoft article I found that mentions the specific limitation of DropDowns, return values & postbacks. I haven't digged deep into their solution and not sure time will allow me to. Mainly posting it in case my solution fails down the road or doesn't work for someone else.


Intuitively you might think adding a confirm dialog box for a
DropDownList is identical to adding such a dialog box for a Button Web
control. That is, simply set the DropDownList's client-side onchange
attribute to something like: return confirm(...);. using:
DropDownListID.Attributes("onchange") = "return confirm(...);"
Unfortunately, this won't work as desired because an AutoPostBack
DropDownList's onchange attribute will be set to a bit of JavaScript
that causes a postback, namely a call to the client-side __doPostBack
function. When setting the onchange attribute programmatically
yourself, the end result is that the rendered client-side onchange
event handler has both your code and the call to __doPostBack:


The article is long so search for "Confirmation with AutoPostBack DropDownLists"

https://msdn.microsoft.com/en-us/library/aa479302.aspx

Answer

There are 2 solutions.

Solution 1: A better work around than adding a link button surrounded by hidden span tags is to add the following to the page load event. This ensures that the function __doPostBack is available.

protected void Page_Load(object sender, EventArgs e)
{
    Page.ClientScript.GetPostBackEventReference(this, string.Empty);
}

The function __doPostBack is generated only if a control in the form needs it to perform postbacks. This includes controls like the LinkButton and other controls for which AutoPostBack is set to true. In fact, only the Button and ImageButton controls can perform postbacks without __doPostBack (see this article). For example, we can see in the HTML output that a LinkButton is rendered this way:

<a id="lnk" href="javascript:__doPostBack(&#39;lnk&#39;,&#39;&#39;)">My link</a>


Solution 2: The following approach achieves the same thing without using __doPostBack.

In the present case, you could set AutoPostBack="true" for the DropDownList:

<asp:DropDownList AutoPostBack="true" onchange="if (!confirmPostBack(this)) return false;" ... >

The onchange event handler would return false when you want to prevent the postback. The Javascript function could be something like this:

function confirmPostBack(ddl)
{
    if (condition) {
        ...
        return true;
    } 
    else {
        ...
        return false;
    }
}

Important: The onchange event handler should not return anything to allow the postback to occur. You can use this syntax:

onchange="if (!confirmPostBack(this)) return false;"

For reasons probably explained in the article mentioned in the question, the following syntax does not work. Returning true still prevents the postback.

onchange="return confirmPostBack(this);" // Does not work!