Monday, March 26, 2012

ListSearchExtender causing postback twice

I was wondering if anyone else has noticed this. When a DropDownList control is extended with ListSearchExtender, and the DropDownList has the AutoPostBack property set to true, the page loads twice. If you step through the debugger you will see OnInit, OnPrerender, Page_Load, etc. being called twice.

Does anyone have a workaround to prevent this?

Thanks,

Carl

Hi Carl,

I'll try to reproduce this to see if I can work out what is going on. Do you have a simple page with just a DropDownList and the extender on it? (No UpdatePanels etc).

Thanks,

Damian


Weeeeell...

This is intereesting. ListSearch only causes double postback when a breakpoint is set. I put together the following code. If you set a breakpoint anywhere in the code-behind, clicking the ListSearch-enabled DropDownList will post back twice. But if you do not have a breakpoint, it posts back once. It still is behavior that doesn't occur without the ListSearch, but at least it isn't REALLY posting twice. Any idea why this is occurring?

Thanks,

Carl

.aspx code:

<%@.PageAutoEventWireup="true"CodeFile="MaskedEditTest.aspx.cs"

Culture="auto"Inherits="MaskedEditTest"

Language="C#"Title="MaskedEdit/ListSearch Example"

UICulture="auto" %>

<%@.RegisterAssembly="AjaxControlToolkit"

Namespace="AjaxControlToolkit"TagPrefix="ajaxToolkit" %>

<!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<htmlxmlns="http://www.w3.org/1999/xhtml">

<headid="Head1"runat="server">

<title>Untitled Page</title>

</head>

<body>

<formid="form1"runat="server">

<div>

<ajaxToolkit:ToolkitScriptManagerrunat="server"

ID="ScriptManager1"EnableScriptGlobalization="true"

EnableScriptLocalization="true"/>

DropDownList without ListSearch. Click on

a selection.

<asp:DropDownListID="DropDownList1"runat="server"

AutoPostBack="true">

<asp:ListItemText="select one"></asp:ListItem>

<asp:ListItemText="hello"></asp:ListItem>

<asp:ListItemText="goodbye"></asp:ListItem>

</asp:DropDownList>

<br/>

<br/>

<asp:LabelID="Label1"runat="server"Text="Postback count: "></asp:Label>

<asp:LabelID="Label2"runat="server"Text="0"></asp:Label>

<br/>

<br/>

DropDownList with ListSearch. Click on a

selection.

<asp:DropDownListID="DropDownList2"runat="server"

AutoPostBack="true">

<asp:ListItemText="hello"></asp:ListItem>

<asp:ListItemText="goodbye"></asp:ListItem>

</asp:DropDownList>

<ajaxToolkit:ListSearchExtenderID="ListSearchExtender1"

runat="server"PromptPosition="top"PromptText="Type to search"

TargetControlID="DropDownList2">

</ajaxToolkit:ListSearchExtender>

<asp:TextBoxID="TextBox1"runat="server"

/>

<asp:ImageButtonID="ImgBntCalc"runat="server"

ImageUrl="~/images/Calendar_scheduleHS.png"

CausesValidation="False"/>

<ajaxToolkit:MaskedEditExtenderID="MaskedEditExtender1"

runat="server"TargetControlID="TextBox1"

Mask="99/99/9999"MessageValidatorTip="true"

CultureName="en-US"

MaskType="Date"

DisplayMoney="Left"AcceptNegative="Left"

ErrorTooltipEnabled="True"/>

<ajaxToolkit:MaskedEditValidatorID="MaskedEditValidator1"

runat="server"ControlExtender="MaskedEditExtender1"

ControlToValidate="TextBox1"EmptyValueMessage="Date is required"

InvalidValueMessage="Date is invalid"Display="Dynamic"

TooltipMessage="Input a date"EmptyValueBlurredText="*"

InvalidValueBlurredMessage="*"ValidationGroup="MKE"/>

<ajaxToolkit:CalendarExtenderID="CalendarExtender1"

runat="server"Format="MM/dd/yyyy"TargetControlID="TextBox1"

PopupButtonID="ImgBntCalc"/>

<br/>

<asp:Buttonrunat="server"ID="resetButton"Text="Reset count"OnClick="resetButton_OnClick"/>

</div>

</form>

</body>

</html>

.cs code:

using System;

using System.Data;

using System.Configuration;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web.UI.HtmlControls;

///<summary>

/// Summary description for MaskedEdit

///</summary>

publicpartialclassMaskedEditTest :Page

{

privatestaticint dropDownListPostCount = 0;protectedoverridevoid OnPreInit(EventArgs e)

{

base.OnPreInit(e);

}

protectedoverridevoid OnInit(EventArgs e)

{

base.OnInit(e);

}

protectedoverridevoid OnLoad(EventArgs e)

{

base.OnLoad(e);

}

protectedoverridevoid OnPreRender(EventArgs e)

{

base.OnPreRender(e);

if (this.IsPostBack)

{

dropDownListPostCount++;

Label2.Text = dropDownListPostCount.ToString();

}

}

protectedvoid resetButton_OnClick(object sender,EventArgs e)

{

dropDownListPostCount = -1;

}

}


More importantly is the problem of ListSearchExtender not working with CascadingDropDownExtender. This one is easy to see. Just attach both extenders to a DropDownList (like the one in the sample web site) and when you close the form or click on another page, it throws a javascript null exception. I have documented this at CodePlex as ID# 8887.

Thanks,

Carl


Hi Carl,

I'm guessing that you are seeing multiple postbacks because the SELECT is losing focus several times as the debugger takes focus away, and gives it back -- the extender fires the OnChange when the SELECT loses focus.

With regards to the error with the CascadingDropDownExtender, I have not managed to reproduce this -- I added ListSearchExtenders to each of the lists on the CascadingDropDown example in the toolkit and had no issues -- could you perhaps post a small example where you are getting an error?

Thanks,

Damian


Hi, Damian. Sorry for the delay in getting back to you.

If you download the "How do I?" demo for CascadingDropDown found athttp://www.asp.net/learn/videos/view.aspx?tabid=63&id=77 and add ListSearch to it, you will see the problem. (You will have to update the AjaxToolkit.dll, since that how-to was written prior to ListSearchExtender.) If you add the following lines to Default.aspx between the opening form tag and the opening table tag that contains the 3 dropdownlists, you will see what I mean:

<ajaxToolkit:ListSearchExtender ID="ListSearchExtender1"
runat="server" TargetControlID="DropDownList1">
</ajaxToolkit:ListSearchExtender>
<ajaxToolkit:ListSearchExtender ID="ListSearchExtender2"
runat="server" TargetControlID="DropDownList2">
</ajaxToolkit:ListSearchExtender>
<ajaxToolkit:ListSearchExtender ID="ListSearchExtender3"
runat="server" TargetControlID="DropDownList3">
</ajaxToolkit:ListSearchExtender>

It will run fine, but when you close the page, or try to go to a different URL, you will get the following message:

Sys.InvalidOperationException: Handler was not added through the Sys.UI.DomEvent.addHandler method.

I would really like to use these two extenders together. Could you look into this?

Thanks,

Carl


I was able to get ListSearch and CascadingDropDown to work together by removing this line:

$clearHandlers(this.get_element());

from the dispose function in ListSearchBehavior.js. I tried replacing it with this code:

var element =this.get_element();

$removeHandler(element,'focus',this._onFocus);

$removeHandler(element,'blur',this._onBlur);

$removeHandler(element,'keydown',this._onKeyDown);

$removeHandler(element,'keyup',this._onKeyUp);

$removeHandler(element,'keypress',this._onKeyPress);

but it still failed.

What are the consequences of removing this call? I assume it would be a memory leak, but is it a leak on the user's machine that goes away when they navigate to a new page, or when they close the browser? Does it increase with each postback? Does it affect the server? Do the $removeHandler() functions in CascadingDropDownBehavior.js take care of this on behalf of ListSearchExtender (which I assume has something to do with the failure)? etc...

Thanks,

Carl


anyone?


I'll be looking into this in the next day or so and will do my best to get a fix into the next toolkit release.

Regards,

Damian


Great!

Thanks, Damian.


I'm about to check in a change to fix this. If you'd like to apply the fix locally to try it out before the next release that would be great.

I've declared a load of member variables:

this._focusHandler =null;

this._blurHandler =null;

this._keyDownHandler =null;

this._keyUpHandler =null;

this._keyPressHandler =null;

I replaced the "AddHandlers" in the "Initialize" with:

this._focusHandler = Function.createDelegate(this,this._onFocus);

this._blurHandler = Function.createDelegate(this,this._onBlur);

this._keyDownHandler = Function.createDelegate(this,this._onKeyDown);

this._keyUpHandler = Function.createDelegate(this,this._onKeyUp);

this._keyPressHandler = Function.createDelegate(this,this._onKeyPress);

$addHandler(element,"focus",this._focusHandler);

$addHandler(element,"blur",this._blurHandler);

$addHandler(element,"keydown",this._keyDownHandler);

$addHandler(element,"keyup",this._keyUpHandler);

$addHandler(element,"keypress",this._keyPressHandler);

In the 'dispose' I replaced the 'clearHandlers' with:

var element =this.get_element();

$removeHandler(element,"focus",this._focusHandler);

$removeHandler(element,"blur",this._blurHandler);

$removeHandler(element,"keydown",this._keyDownHandler);

$removeHandler(element,"keyup",this._keyUpHandler);

$removeHandler(element,"keypress",this._keyPressHandler);

Regards,

Damian


Cool! Thanks, Damian. I'll give it a try and let you know how it goes.

Thanks,

Carl

No comments:

Post a Comment