Ajax UpdatePanel DropDownList auto-repeat problem.

Discussion in 'ASP .Net' started by cmeek1_1999, Sep 25, 2008.

  1. cmeek1_1999

    cmeek1_1999 Guest

    Hello,

    On a webpage, create an UpdatePanel with two DropDownLists.
    Set AutoPostBack of DropDownList1 to true.
    In the SelectedIndexChanged method, refill DropDownList2 and set the focus
    to DropDownList1 using the ScriptManager SetFocus method.

    Use the Visual Studio debugger.
    Set a breakpoint on in the (!IsPostBack) part of the PageLoad method.
    Start the web application and continue after the breakpoint has been reached.
    Press once the down-arrow on the DropDownList1.
    An update of DropDownList2 will occur as expected.

    Press and hold the down-arrow (or up-arrow) so the auto-repeat sets in.
    From time to time (not always) the breakpoint gets reached, which is highly
    unexpected.

    Two questions.

    1) Why does this happen?
    2) What can I do to prevent this from happening without losing focus and
    auto-repeat functionality?

    Regards,

    Carlo Mekenkamp

    default.aspx.cs
    ---8<---
    using System;
    using System.Web.UI.WebControls;

    namespace AjaxDdlTest
    {
    public partial class _Default : System.Web.UI.Page
    {
    protected void Page_Load(object sender, EventArgs e)
    {
    if (!IsPostBack)
    {
    DropDownList1.DataBind(); //breakpoint here
    DropDownList1.SelectedValue = "0";
    DropDownList2.DataBind();
    DropDownList1.Focus();
    }
    }

    protected void DropDownList1_SelectedIndexChanged(object sender,
    EventArgs e)
    {
    DropDownList ddl = (DropDownList)sender;
    DropDownList2.DataBind();
    ScriptManager1.SetFocus(ddl);
    }

    protected void DropDownList1_DataBinding(object sender, EventArgs e)
    {
    DropDownList ddl = (DropDownList)sender;
    ddl.Items.Clear();
    for (int i = 0; i < 200; i++)
    {
    ddl.Items.Add(i.ToString());
    }
    }

    protected void DropDownList2_DataBinding(object sender, EventArgs e)
    {
    DropDownList ddl = (DropDownList)sender;
    ddl.Items.Clear();
    for (int i = int.Parse(DropDownList1.SelectedValue); i < 200; i++)
    {
    ddl.Items.Add(i.ToString());
    }
    }
    }
    }
    ---8<---
    default.aspx
    ---8<---
    <%@ Page Language="C#" AutoEventWireup="true" Codebehind="Default.aspx.cs"
    Inherits="AjaxDdlTest._Default" %>

    <!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>Untitled Page</title>
    </head>
    <body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server" />
    <div>
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
    <ContentTemplate>
    <asp:DropDownList ID="DropDownList1" runat="server"
    AutoPostBack="true" OnDataBinding="DropDownList1_DataBinding"

    OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged" />
    <br />
    <asp:DropDownList ID="DropDownList2" runat="server"
    AutoPostBack="true" OnDataBinding="DropDownList2_DataBinding" />
    </ContentTemplate>
    </asp:UpdatePanel>
    </div>
    </form>
    </body>
    </html>
    ---8<---
     
    cmeek1_1999, Sep 25, 2008
    #1
    1. Advertising

  2. cmeek1_1999

    bruce barker Guest

    this is one of the problems of using autopostback with a dropdown.
    becuase the onclick/onchange fires as the down arrow is used, a postback
    is fired on each selection. any postback causes the dropdown to be built
    by the browser.

    a quick hack is to have client code attached to the onchange disable the
    select, then on rerender enable it again. a better approach is to use a
    timer to only fire the postback when the user pauses in selecting. the
    best is to not use a postback on a dropdown, but some other ajax method.

    -- bruce (sqlwork.com)

    cmeek1_1999 wrote:
    > Hello,
    >
    > On a webpage, create an UpdatePanel with two DropDownLists.
    > Set AutoPostBack of DropDownList1 to true.
    > In the SelectedIndexChanged method, refill DropDownList2 and set the focus
    > to DropDownList1 using the ScriptManager SetFocus method.
    >
    > Use the Visual Studio debugger.
    > Set a breakpoint on in the (!IsPostBack) part of the PageLoad method.
    > Start the web application and continue after the breakpoint has been reached.
    > Press once the down-arrow on the DropDownList1.
    > An update of DropDownList2 will occur as expected.
    >
    > Press and hold the down-arrow (or up-arrow) so the auto-repeat sets in.
    > From time to time (not always) the breakpoint gets reached, which is highly
    > unexpected.
    >
    > Two questions.
    >
    > 1) Why does this happen?
    > 2) What can I do to prevent this from happening without losing focus and
    > auto-repeat functionality?
    >
    > Regards,
    >
    > Carlo Mekenkamp
    >
    > default.aspx.cs
    > ---8<---
    > using System;
    > using System.Web.UI.WebControls;
    >
    > namespace AjaxDdlTest
    > {
    > public partial class _Default : System.Web.UI.Page
    > {
    > protected void Page_Load(object sender, EventArgs e)
    > {
    > if (!IsPostBack)
    > {
    > DropDownList1.DataBind(); //breakpoint here
    > DropDownList1.SelectedValue = "0";
    > DropDownList2.DataBind();
    > DropDownList1.Focus();
    > }
    > }
    >
    > protected void DropDownList1_SelectedIndexChanged(object sender,
    > EventArgs e)
    > {
    > DropDownList ddl = (DropDownList)sender;
    > DropDownList2.DataBind();
    > ScriptManager1.SetFocus(ddl);
    > }
    >
    > protected void DropDownList1_DataBinding(object sender, EventArgs e)
    > {
    > DropDownList ddl = (DropDownList)sender;
    > ddl.Items.Clear();
    > for (int i = 0; i < 200; i++)
    > {
    > ddl.Items.Add(i.ToString());
    > }
    > }
    >
    > protected void DropDownList2_DataBinding(object sender, EventArgs e)
    > {
    > DropDownList ddl = (DropDownList)sender;
    > ddl.Items.Clear();
    > for (int i = int.Parse(DropDownList1.SelectedValue); i < 200; i++)
    > {
    > ddl.Items.Add(i.ToString());
    > }
    > }
    > }
    > }
    > ---8<---
    > default.aspx
    > ---8<---
    > <%@ Page Language="C#" AutoEventWireup="true" Codebehind="Default.aspx.cs"
    > Inherits="AjaxDdlTest._Default" %>
    >
    > <!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>Untitled Page</title>
    > </head>
    > <body>
    > <form id="form1" runat="server">
    > <asp:ScriptManager ID="ScriptManager1" runat="server" />
    > <div>
    > <asp:UpdatePanel ID="UpdatePanel1" runat="server">
    > <ContentTemplate>
    > <asp:DropDownList ID="DropDownList1" runat="server"
    > AutoPostBack="true" OnDataBinding="DropDownList1_DataBinding"
    >
    > OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged" />
    > <br />
    > <asp:DropDownList ID="DropDownList2" runat="server"
    > AutoPostBack="true" OnDataBinding="DropDownList2_DataBinding" />
    > </ContentTemplate>
    > </asp:UpdatePanel>
    > </div>
    > </form>
    > </body>
    > </html>
    > ---8<---
     
    bruce barker, Sep 25, 2008
    #2
    1. Advertising

  3. cmeek1_1999

    cmeek1_1999 Guest

    Thank you for responding.

    When I disabled the select on the onchange, the focus was lost,
    so that was no good solution.
    Setting a timer was a better solution. I implemented it like below.
    Or should I make an Ajax Extender to handle this?
    Letting another control return was not an option I think.

    Regards,

    Carlo Mekenkamp

    protected void Page_Load(object sender, EventArgs e)
    {
    if (!IsPostBack)
    {
    string ddl_timeout_id = DropDownList1.ClientID + "_timeoutId";
    string ddl_submit = DropDownList1.ClientID + "_submit";
    string delayscript =
    @"var " + ddl_timeout_id + @"=0;
    function " + ddl_submit + @"()
    {
    clearTimeout(" + ddl_timeout_id + @");
    " + ddl_timeout_id + @"=setTimeout('" +
    ClientScript.GetPostBackEventReference(DropDownList1,
    string.Empty).Replace(@"'", @"\'")
    + @"', 500);
    return true;
    }";
    ClientScript.RegisterClientScriptBlock(typeof(_Default),
    ddl_submit, delayscript, true);
    DropDownList1.DataBind(); //breakpoint here
    DropDownList1.Attributes["onchange"] = @"return " +
    ddl_submit + @"();alert('Bug:No return');";
    DropDownList1.SelectedValue = "0";
    DropDownList2.DataBind();
    DropDownList1.Focus();
    }
    }


    "bruce barker" wrote:

    > this is one of the problems of using autopostback with a dropdown.
    > becuase the onclick/onchange fires as the down arrow is used, a postback
    > is fired on each selection. any postback causes the dropdown to be built
    > by the browser.
    >
    > a quick hack is to have client code attached to the onchange disable the
    > select, then on rerender enable it again. a better approach is to use a
    > timer to only fire the postback when the user pauses in selecting. the
    > best is to not use a postback on a dropdown, but some other ajax method.
    >
    > -- bruce (sqlwork.com)
    >
    > cmeek1_1999 wrote:
    > > Hello,
    > >
    > > On a webpage, create an UpdatePanel with two DropDownLists.
    > > Set AutoPostBack of DropDownList1 to true.
    > > In the SelectedIndexChanged method, refill DropDownList2 and set the focus
    > > to DropDownList1 using the ScriptManager SetFocus method.
    > >
    > > Use the Visual Studio debugger.
    > > Set a breakpoint on in the (!IsPostBack) part of the PageLoad method.
    > > Start the web application and continue after the breakpoint has been reached.
    > > Press once the down-arrow on the DropDownList1.
    > > An update of DropDownList2 will occur as expected.
    > >
    > > Press and hold the down-arrow (or up-arrow) so the auto-repeat sets in.
    > > From time to time (not always) the breakpoint gets reached, which is highly
    > > unexpected.
    > >
    > > Two questions.
    > >
    > > 1) Why does this happen?
    > > 2) What can I do to prevent this from happening without losing focus and
    > > auto-repeat functionality?
    > >
    > > Regards,
    > >
    > > Carlo Mekenkamp
    > >
    > > default.aspx.cs
    > > ---8<---
    > > using System;
    > > using System.Web.UI.WebControls;
    > >
    > > namespace AjaxDdlTest
    > > {
    > > public partial class _Default : System.Web.UI.Page
    > > {
    > > protected void Page_Load(object sender, EventArgs e)
    > > {
    > > if (!IsPostBack)
    > > {
    > > DropDownList1.DataBind(); //breakpoint here
    > > DropDownList1.SelectedValue = "0";
    > > DropDownList2.DataBind();
    > > DropDownList1.Focus();
    > > }
    > > }
    > >
    > > protected void DropDownList1_SelectedIndexChanged(object sender,
    > > EventArgs e)
    > > {
    > > DropDownList ddl = (DropDownList)sender;
    > > DropDownList2.DataBind();
    > > ScriptManager1.SetFocus(ddl);
    > > }
    > >
    > > protected void DropDownList1_DataBinding(object sender, EventArgs e)
    > > {
    > > DropDownList ddl = (DropDownList)sender;
    > > ddl.Items.Clear();
    > > for (int i = 0; i < 200; i++)
    > > {
    > > ddl.Items.Add(i.ToString());
    > > }
    > > }
    > >
    > > protected void DropDownList2_DataBinding(object sender, EventArgs e)
    > > {
    > > DropDownList ddl = (DropDownList)sender;
    > > ddl.Items.Clear();
    > > for (int i = int.Parse(DropDownList1.SelectedValue); i < 200; i++)
    > > {
    > > ddl.Items.Add(i.ToString());
    > > }
    > > }
    > > }
    > > }
    > > ---8<---
    > > default.aspx
    > > ---8<---
    > > <%@ Page Language="C#" AutoEventWireup="true" Codebehind="Default.aspx.cs"
    > > Inherits="AjaxDdlTest._Default" %>
    > >
    > > <!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>Untitled Page</title>
    > > </head>
    > > <body>
    > > <form id="form1" runat="server">
    > > <asp:ScriptManager ID="ScriptManager1" runat="server" />
    > > <div>
    > > <asp:UpdatePanel ID="UpdatePanel1" runat="server">
    > > <ContentTemplate>
    > > <asp:DropDownList ID="DropDownList1" runat="server"
    > > AutoPostBack="true" OnDataBinding="DropDownList1_DataBinding"
    > >
    > > OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged" />
    > > <br />
    > > <asp:DropDownList ID="DropDownList2" runat="server"
    > > AutoPostBack="true" OnDataBinding="DropDownList2_DataBinding" />
    > > </ContentTemplate>
    > > </asp:UpdatePanel>
    > > </div>
    > > </form>
    > > </body>
    > > </html>
    > > ---8<---

    >
     
    cmeek1_1999, Sep 26, 2008
    #3
  4. cmeek1_1999

    cmeek1_1999 Guest

    I tried writing an Ajax control (my first one) to do it, because I had
    troubles with the script inside a FormView and I wanted the first postback
    without delay.
    Be sure to make AutoPostBackDelayBehavior.js an embedded resource and let
    the ClientScriptResource attribute point to the right place.
    Let the TargetControlId be the Id of the DropDownList, and it seems to work.

    Thanks again.

    Carlo Mekenkamp

    AutoPostBackDelayExtender.cs
    ---8<---
    using System;
    using System.Web.UI.WebControls;
    using System.Web.UI;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using AjaxControlToolkit;

    [assembly:
    System.Web.UI.WebResource("AutoPostBackDelay.AutoPostBackDelayBehavior.js",
    "text/javascript")]

    namespace AutoPostBackDelay
    {
    [Designer(typeof(AutoPostBackDelayDesigner))]
    [ClientScriptResource("AutoPostBackDelay.AutoPostBackDelayBehavior",
    "AutoPostBackDelay.AutoPostBackDelayBehavior.js")]
    [TargetControlType(typeof(Control))]
    public class AutoPostBackDelayExtender : ExtenderControlBase
    {
    // TODO: Add your property accessors here.
    //
    [ExtenderControlProperty]
    [DefaultValue(500)]
    public int DelayTime
    {
    get
    {
    return GetPropertyValue("DelayTime", 500);
    }
    set
    {
    SetPropertyValue("DelayTime", value);
    }
    }
    [ExtenderControlProperty]
    [DefaultValue(600)]
    public int ResetTime
    {
    get
    {
    return GetPropertyValue("ResetTime", 600);
    }
    set
    {
    SetPropertyValue("ResetTime", value);
    }
    }

    /// <summary>
    /// Specifies the script to run to initiate a postback
    /// </summary>
    [ExtenderControlProperty]
    [ClientPropertyName("postBackScript")]
    [DefaultValue("")]
    [Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    public string PostBackScript
    {
    get
    {
    return GetPropertyValue("PostBackScript", string.Empty);
    }
    set
    {
    SetPropertyValue("PostBackScript", value);
    }
    }

    protected override void OnLoad(EventArgs e)
    {
    base.OnLoad(e);
    PostBackScript =
    Page.ClientScript.GetPostBackEventReference(TargetControl, "");
    }
    }
    }
    ---8<---
    AutoPostBackDelayDesigner.cs
    ---8<---
    using System.Web.UI.WebControls;
    using System.Web.UI;

    namespace AutoPostBackDelay
    {
    class AutoPostBackDelayDesigner :
    AjaxControlToolkit.Design.ExtenderControlBaseDesigner<AutoPostBackDelayExtender>
    {


    }
    }
    ---8<---
    AutoPostBackDelayBehavior.js
    ---8<---
    Type.registerNamespace('AutoPostBackDelay');

    AutoPostBackDelay.AutoPostBackDelayBehavior = function(element) {
    AutoPostBackDelay.AutoPostBackDelayBehavior.initializeBase(this,
    [element]);

    // TODO : (Step 1) Add your property variables here
    this._DelayTimeValue = 500;
    this._ResetTimeValue = 600;
    this._CurrentDelayTimeValue = 0;
    this._DelayId = 0;
    this._ResetId = 0;
    // Script to call to initiate a postback
    this._postBackScript = null;
    this._changeHandler = null;
    this._oldScript = null;
    }
    AutoPostBackDelay.AutoPostBackDelayBehavior.prototype = {
    initialize : function() {
    AutoPostBackDelay.AutoPostBackDelayBehavior.callBaseMethod(this,
    'initialize');

    var element = this.get_element();

    // Attach the handler
    this._changeHandler = Function.createDelegate(this, this._onChange);
    $addHandler(element, "change", this._changeHandler);

    this._oldScript = element.getAttribute("onchange");
    if (this._oldScript) {
    element.setAttribute("onchange", null);
    }
    // TODO: Add your initalization code here
    },

    dispose : function() {
    // TODO: Add your cleanup code here
    clearTimeout(this._ResetId);
    clearTimeout(this._DelayId);
    this._CurrentDelayTimeValue = 0;
    // Detach event handlers
    if (this._changeHandler) {
    $removeHandler(this.get_element(), "change", this._changeHandler);
    this._changeHandler = null;
    }

    if (this._oldScript) {
    this.get_element().setAttribute("onchange", this._oldScript);
    this._oldScript = null;
    }

    AutoPostBackDelay.AutoPostBackDelayBehavior.callBaseMethod(this,
    'dispose');
    },

    // TODO: (Step 2) Add your property accessors here
    _onChange : function() {
    var e = this.get_element();
    if (e) {
    clearTimeout(this._ResetId);
    clearTimeout(this._DelayId);
    this._DelayId = setTimeout(Function.createDelegate(this,
    this._postBack), this._CurrentDelayTimeValue);
    this._ResetId = setTimeout(Function.createDelegate(this,
    this._reset), this._ResetTimeValue);
    this._CurrentDelayTimeValue = this._DelayTimeValue;
    return false;
    }
    },

    _reset : function() {
    this._CurrentDelayTimeValue = 0;
    },

    _postBack : function() {
    if (this._postBackScript) {
    eval(this._postBackScript);
    }
    },

    get_postBackScript : function() {
    /// <value type="String">
    /// Script to run to initiate a postback
    /// </value>
    return this._postBackScript;
    },
    set_postBackScript : function(value) {
    if (this._postBackScript != value) {
    this._postBackScript = value;
    this.raisePropertyChanged('postBackScript');
    }
    },

    get_DelayTime : function() {
    return this._DelayTimeValue;
    },
    set_DelayTime : function(value) {
    this._DelayTimeValue = value;
    },

    get_ResetTime : function() {
    return this._ResetTimeValue;
    },
    set_ResetTime : function(value) {
    this._ResetTimeValue = value;
    }
    }
    AutoPostBackDelay.AutoPostBackDelayBehavior.registerClass('AutoPostBackDelay.AutoPostBackDelayBehavior', AjaxControlToolkit.BehaviorBase);
    ---8<---
     
    cmeek1_1999, Sep 27, 2008
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?Sm9lIFNodW0=?=
    Replies:
    2
    Views:
    1,516
    Eliyahu Goldin
    Sep 5, 2004
  2. retroman80s
    Replies:
    2
    Views:
    789
    retroman80s
    Mar 5, 2007
  3. Replies:
    3
    Views:
    481
    Rob Meade
    Aug 8, 2007
  4. linkswanted
    Replies:
    1
    Views:
    922
  5. Nathan Sokalski
    Replies:
    1
    Views:
    589
    miher
    Jun 15, 2009
Loading...

Share This Page